dyld-640.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 "Loading.h"
44 #include "Logging.h"
45 #include "Diagnostics.h"
46 #include "DyldSharedCache.h"
47 #include "APIs.h"
48
49
50 namespace dyld3 {
51
52 // from APIs.cpp
53 void parseDlHandle(void* h, const MachOLoaded** mh, bool* dontContinue);
54
55
56 // only in macOS and deprecated
57 #if __MAC_OS_X_VERSION_MIN_REQUIRED
58
59 // macOS needs to support an old API that only works with fileype==MH_BUNDLE.
60 // In this deprecated API (unlike dlopen), loading and linking are separate steps.
61 // NSCreateObjectFileImageFrom*() just maps in the bundle mach-o file.
62 // NSLinkModule() does the load of dependent modules and rebasing/binding.
63 // To unload one of these, you must call NSUnLinkModule() and NSDestroyObjectFileImage() in any order!
64 //
65
66 NSObjectFileImageReturnCode NSCreateObjectFileImageFromFile(const char* path, NSObjectFileImage* ofi)
67 {
68 log_apis("NSCreateObjectFileImageFromFile(\"%s\", %p)\n", path, ofi);
69
70 // verify path exists
71 struct stat statbuf;
72 if ( ::stat(path, &statbuf) == -1 )
73 return NSObjectFileImageFailure;
74
75 // create ofi that just contains path. NSLinkModule does all the work
76 OFIInfo result;
77 result.path = strdup(path);
78 result.memSource = nullptr;
79 result.memLength = 0;
80 result.loadAddress = nullptr;
81 result.imageNum = 0;
82 *ofi = gAllImages.addNSObjectFileImage(result);
83
84 log_apis("NSCreateObjectFileImageFromFile() => %p\n", *ofi);
85
86 return NSObjectFileImageSuccess;
87 }
88
89 NSObjectFileImageReturnCode NSCreateObjectFileImageFromMemory(const void* memImage, size_t memImageSize, NSObjectFileImage *ofi)
90 {
91 log_apis("NSCreateObjectFileImageFromMemory(%p, 0x%0lX, %p)\n", memImage, memImageSize, ofi);
92
93 // sanity check the buffer is a mach-o file
94 __block Diagnostics diag;
95
96 // check if it is current arch mach-o or fat with slice for current arch
97 bool usable = false;
98 const MachOFile* mf = (MachOFile*)memImage;
99 if ( mf->hasMachOMagic() && mf->isMachO(diag, memImageSize) ) {
100 if ( strcmp(mf->archName(), MachOFile::currentArchName()) == 0 )
101 usable = true;
102 #if __x86_64__
103 // <rdar://problem/42727628> support thin x86_64 on haswell machines
104 else if ( (strcmp(MachOFile::currentArchName(), "x86_64h") == 0) && (strcmp(mf->archName(), "x86_64") == 0) )
105 usable = true;
106 #endif
107 }
108 else if ( const FatFile* ff = FatFile::isFatFile(memImage) ) {
109 uint64_t sliceOffset;
110 uint64_t sliceLen;
111 bool missingSlice;
112 if ( ff->isFatFileWithSlice(diag, memImageSize, MachOFile::currentArchName(), sliceOffset, sliceLen, missingSlice) ) {
113 mf = (MachOFile*)((long)memImage+sliceOffset);
114 if ( mf->isMachO(diag, sliceLen) ) {
115 usable = true;
116 }
117 }
118 }
119 if ( usable ) {
120 if ( !mf->supportsPlatform(Platform::macOS) )
121 usable = false;
122 }
123 if ( !usable ) {
124 log_apis("NSCreateObjectFileImageFromMemory() not mach-o\n");
125 return NSObjectFileImageFailure;
126 }
127
128 // this API can only be used with bundles
129 if ( !mf->isBundle() ) {
130 log_apis("NSCreateObjectFileImageFromMemory() not a bundle\n");
131 return NSObjectFileImageInappropriateFile;
132 }
133
134 // allocate ofi that just lists the memory range
135 OFIInfo result;
136 result.path = nullptr;
137 result.memSource = memImage;
138 result.memLength = memImageSize;
139 result.loadAddress = nullptr;
140 result.imageNum = 0;
141 *ofi = gAllImages.addNSObjectFileImage(result);
142
143 log_apis("NSCreateObjectFileImageFromMemory() => %p\n", *ofi);
144
145 return NSObjectFileImageSuccess;
146 }
147
148 NSModule NSLinkModule(NSObjectFileImage ofi, const char* moduleName, uint32_t options)
149 {
150 DYLD_LOAD_LOCK_THIS_BLOCK
151 log_apis("NSLinkModule(%p, \"%s\", 0x%08X)\n", ofi, moduleName, options);
152
153 __block const char* path = nullptr;
154 bool foundImage = gAllImages.forNSObjectFileImage(ofi, ^(OFIInfo &image) {
155 // if this is memory based image, write to temp file, then use file based loading
156 if ( image.memSource != nullptr ) {
157 // make temp file with content of memory buffer
158 bool successfullyWritten = false;
159 image.path = ::tempnam(nullptr, "NSCreateObjectFileImageFromMemory-");
160 if ( image.path != nullptr ) {
161 int fd = ::open(image.path, O_WRONLY | O_CREAT | O_EXCL, 0644);
162 if ( fd != -1 ) {
163 ssize_t writtenSize = ::pwrite(fd, image.memSource, image.memLength, 0);
164 if ( writtenSize == image.memLength )
165 successfullyWritten = true;
166 ::close(fd);
167 }
168 }
169 if ( !successfullyWritten ) {
170 if ( image.path != nullptr ) {
171 free((void*)image.path);
172 image.path = nullptr;
173 }
174 log_apis("NSLinkModule() => NULL (could not save memory image to temp file)\n");
175 return;
176 }
177 }
178 path = image.path;
179 });
180
181 if (!foundImage) {
182 // ofi is invalid if not in list
183 log_apis("NSLinkModule() => NULL (invalid NSObjectFileImage)\n");
184 return nullptr;
185 }
186
187 if (!path)
188 return nullptr;
189
190 // dlopen the binary outside of the read lock as we don't want to risk deadlock
191 Diagnostics diag;
192 void* callerAddress = __builtin_return_address(1); // note layers: 1: real client, 0: libSystem glue
193 const MachOLoaded* loadAddress = gAllImages.dlopen(diag, path, false, false, false, true, callerAddress);
194 if ( diag.hasError() ) {
195 log_apis(" NSLinkModule: failed: %s\n", diag.errorMessage());
196 return nullptr;
197 }
198
199 // Now update the load address of this object
200 gAllImages.forNSObjectFileImage(ofi, ^(OFIInfo &image) {
201 image.loadAddress = loadAddress;
202
203 // if memory based load, delete temp file
204 if ( image.memSource != nullptr ) {
205 log_apis(" NSLinkModule: delete temp file: %s\n", image.path);
206 ::unlink(image.path);
207 }
208 });
209
210 log_apis("NSLinkModule() => %p\n", loadAddress);
211 return (NSModule)loadAddress;
212 }
213
214 // NSUnLinkModule unmaps the image, but does not release the NSObjectFileImage
215 bool NSUnLinkModule(NSModule module, uint32_t options)
216 {
217 DYLD_LOAD_LOCK_THIS_BLOCK
218 log_apis("NSUnLinkModule(%p, 0x%08X)\n", module, options);
219
220 __block const mach_header* mh = nullptr;
221 gAllImages.infoForImageMappedAt(module, ^(const LoadedImage& foundImage, uint8_t permissions) {
222 mh = foundImage.loadedAddress();
223 });
224
225 if ( mh != nullptr )
226 gAllImages.decRefCount(mh); // removes image if reference count went to zero
227
228 log_apis("NSUnLinkModule() => %d\n", mh != nullptr);
229
230 return mh != nullptr;
231 }
232
233 // NSDestroyObjectFileImage releases the NSObjectFileImage, but the mapped image may remain in use
234 bool NSDestroyObjectFileImage(NSObjectFileImage imageHandle)
235 {
236 log_apis("NSDestroyObjectFileImage(%p)\n", imageHandle);
237
238 __block const void* memSource = nullptr;
239 __block size_t memLength = 0;
240 __block const char* path = nullptr;
241 bool foundImage = gAllImages.forNSObjectFileImage(imageHandle, ^(OFIInfo &image) {
242 // keep copy of info
243 memSource = image.memSource;
244 memLength = image.memLength;
245 path = image.path;
246 });
247
248 if (!foundImage)
249 return false;
250
251 // remove from list
252 gAllImages.removeNSObjectFileImage(imageHandle);
253
254 // if object was created from a memory, release that memory
255 // NOTE: this is the way dyld has always done this. NSCreateObjectFileImageFromMemory() hands ownership of the memory to dyld
256 if ( memSource != nullptr ) {
257 // we don't know if memory came from malloc or vm_allocate, so ask malloc
258 if ( malloc_size(memSource) != 0 )
259 free((void*)(memSource));
260 else
261 vm_deallocate(mach_task_self(), (vm_address_t)memSource, memLength);
262 }
263 free((void*)path);
264
265 return true;
266 }
267
268 uint32_t NSSymbolDefinitionCountInObjectFileImage(NSObjectFileImage objectFileImage)
269 {
270 halt("NSSymbolDefinitionCountInObjectFileImage() is obsolete");
271 }
272
273 const char* NSSymbolDefinitionNameInObjectFileImage(NSObjectFileImage objectFileImage, uint32_t ordinal)
274 {
275 halt("NSSymbolDefinitionNameInObjectFileImage() is obsolete");
276 }
277
278 uint32_t NSSymbolReferenceCountInObjectFileImage(NSObjectFileImage objectFileImage)
279 {
280 halt("NSSymbolReferenceCountInObjectFileImage() is obsolete");
281 }
282
283 const char* NSSymbolReferenceNameInObjectFileImage(NSObjectFileImage objectFileImage, uint32_t ordinal, bool *tentative_definition)
284 {
285 halt("NSSymbolReferenceNameInObjectFileImage() is obsolete");
286 }
287
288 bool NSIsSymbolDefinedInObjectFileImage(NSObjectFileImage imageHandle, const char* symbolName)
289 {
290 log_apis("NSIsSymbolDefinedInObjectFileImage(%p, %s)\n", imageHandle, symbolName);
291
292 __block bool hasSymbol = false;
293 bool foundImage = gAllImages.forNSObjectFileImage(imageHandle, ^(OFIInfo &image) {
294 void* addr;
295 bool resultPointsToInstructions = false;
296 hasSymbol = image.loadAddress->hasExportedSymbol(symbolName, nullptr, &addr, &resultPointsToInstructions);
297 });
298
299 // ofi is invalid if not in list
300 if (!foundImage)
301 return false;
302
303 return hasSymbol;
304 }
305
306 void* NSGetSectionDataInObjectFileImage(NSObjectFileImage imageHandle, const char* segmentName, const char* sectionName, size_t* size)
307 {
308 __block const void* result = nullptr;
309 bool foundImage = gAllImages.forNSObjectFileImage(imageHandle, ^(OFIInfo &image) {
310 uint64_t sz;
311 result = image.loadAddress->findSectionContent(segmentName, sectionName, sz);
312 *size = (size_t)sz;
313 });
314
315 // ofi is invalid if not in list
316 if (!foundImage)
317 return nullptr;
318
319 return (void*)result;
320 }
321
322 const char* NSNameOfModule(NSModule m)
323 {
324 log_apis("NSNameOfModule(%p)\n", m);
325
326 __block const char* result = nullptr;
327 gAllImages.infoForImageMappedAt(m, ^(const LoadedImage& foundImage, uint8_t permissions) {
328 result = gAllImages.imagePath(foundImage.image());
329 });
330
331 return result;
332 }
333
334 const char* NSLibraryNameForModule(NSModule m)
335 {
336 log_apis("NSLibraryNameForModule(%p)\n", m);
337
338 __block const char* result = nullptr;
339 gAllImages.infoForImageMappedAt(m, ^(const LoadedImage& foundImage, uint8_t permissions) {
340 result = gAllImages.imagePath(foundImage.image());
341 });
342 return result;
343 }
344
345
346 static bool flatFindSymbol(const char* symbolName, void** symbolAddress, const mach_header** foundInImageAtLoadAddress)
347 {
348 __block bool result = false;
349 gAllImages.forEachImage(^(const LoadedImage& loadedImage, bool& stop) {
350 bool resultPointsToInstructions = false;
351 if ( loadedImage.loadedAddress()->hasExportedSymbol(symbolName, nullptr, symbolAddress, &resultPointsToInstructions) ) {
352 *foundInImageAtLoadAddress = loadedImage.loadedAddress();
353 stop = true;
354 result = true;
355 }
356 });
357 return result;
358 }
359
360 bool NSIsSymbolNameDefined(const char* symbolName)
361 {
362 log_apis("NSIsSymbolNameDefined(%s)\n", symbolName);
363
364 const mach_header* foundInImageAtLoadAddress;
365 void* address;
366 return flatFindSymbol(symbolName, &address, &foundInImageAtLoadAddress);
367 }
368
369 bool NSIsSymbolNameDefinedWithHint(const char* symbolName, const char* libraryNameHint)
370 {
371 log_apis("NSIsSymbolNameDefinedWithHint(%s, %s)\n", symbolName, libraryNameHint);
372
373 const mach_header* foundInImageAtLoadAddress;
374 void* address;
375 return flatFindSymbol(symbolName, &address, &foundInImageAtLoadAddress);
376 }
377
378 bool NSIsSymbolNameDefinedInImage(const struct mach_header* mh, const char* symbolName)
379 {
380 log_apis("NSIsSymbolNameDefinedInImage(%p, %s)\n", mh, symbolName);
381
382 void* addr;
383 bool resultPointsToInstructions = false;
384 return ((MachOLoaded*)mh)->hasExportedSymbol(symbolName, nullptr, &addr, &resultPointsToInstructions);
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 const MachOLoaded* mh = (const MachOLoaded*)module;
416 void* addr;
417 bool resultPointsToInstructions = false;
418 if ( mh->hasExportedSymbol(symbolName, nullptr, &addr, &resultPointsToInstructions) ) {
419 return (NSSymbol)addr;
420 }
421 return nullptr;
422 }
423
424 NSSymbol NSLookupSymbolInImage(const mach_header* mh, const char* symbolName, uint32_t options)
425 {
426 log_apis("NSLookupSymbolInImage(%p, \"%s\", 0x%08X)\n", mh, symbolName, options);
427
428 void* addr;
429 bool resultPointsToInstructions = false;
430 if ( ((MachOLoaded*)mh)->hasExportedSymbol(symbolName, nullptr, &addr, &resultPointsToInstructions) ) {
431 log_apis(" NSLookupSymbolInImage() => %p\n", addr);
432 return (NSSymbol)addr;
433 }
434 if ( options & NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR ) {
435 log_apis(" NSLookupSymbolInImage() => NULL\n");
436 return nullptr;
437 }
438 // FIXME: abort();
439 return nullptr;
440 }
441
442 const char* NSNameOfSymbol(NSSymbol symbol)
443 {
444 halt("NSNameOfSymbol() is obsolete");
445 }
446
447 void* NSAddressOfSymbol(NSSymbol symbol)
448 {
449 log_apis("NSAddressOfSymbol(%p)\n", symbol);
450
451 // in dyld 1.0, NSSymbol was a pointer to the nlist entry in the symbol table
452 return (void*)symbol;
453 }
454
455 NSModule NSModuleForSymbol(NSSymbol symbol)
456 {
457 log_apis("NSModuleForSymbol(%p)\n", symbol);
458
459 __block NSModule result = nullptr;
460 gAllImages.infoForImageMappedAt(symbol, ^(const LoadedImage& foundImage, uint8_t permissions) {
461 result = (NSModule)foundImage.loadedAddress();
462 });
463
464 return result;
465 }
466
467 void NSLinkEditError(NSLinkEditErrors *c, int *errorNumber, const char** fileName, const char** errorString)
468 {
469 log_apis("NSLinkEditError(%p, %p, %p, %p)\n", c, errorNumber, fileName, errorString);
470 *c = NSLinkEditOtherError;
471 *errorNumber = 0;
472 *fileName = NULL;
473 *errorString = NULL;
474 }
475
476 bool NSAddLibrary(const char* pathName)
477 {
478 log_apis("NSAddLibrary(%s)\n", pathName);
479
480 void* callerAddress = __builtin_return_address(1); // note layers: 1: real client, 0: libSystem glue
481 return ( dlopen_internal(pathName, 0, callerAddress) != nullptr);
482 }
483
484 bool NSAddLibraryWithSearching(const char* pathName)
485 {
486 log_apis("NSAddLibraryWithSearching(%s)\n", pathName);
487
488 void* callerAddress = __builtin_return_address(1); // note layers: 1: real client, 0: libSystem glue
489 return ( dlopen_internal(pathName, 0, callerAddress) != nullptr);
490 }
491
492 const mach_header* NSAddImage(const char* imageName, uint32_t options)
493 {
494 log_apis("NSAddImage(\"%s\", 0x%08X)\n", imageName, options);
495
496 // Note: this is a quick and dirty implementation that just uses dlopen() and ignores some option flags
497 uint32_t dloptions = 0;
498 if ( (options & NSADDIMAGE_OPTION_RETURN_ONLY_IF_LOADED) != 0 )
499 dloptions |= RTLD_NOLOAD;
500
501 void* callerAddress = __builtin_return_address(1); // note layers: 1: real client, 0: libSystem glue
502 void* h = dlopen_internal(imageName, dloptions, callerAddress);
503 if ( h != nullptr ) {
504 const MachOLoaded* mh;
505 bool dontContinue;
506 parseDlHandle(h, &mh, &dontContinue);
507 return mh;
508 }
509
510 if ( (options & (NSADDIMAGE_OPTION_RETURN_ON_ERROR|NSADDIMAGE_OPTION_RETURN_ONLY_IF_LOADED)) == 0 ) {
511 halt("NSAddImage() image not found");
512 }
513 return nullptr;
514 }
515
516 void NSInstallLinkEditErrorHandlers(const NSLinkEditErrorHandlers *handlers)
517 {
518 halt("NSInstallLinkEditErrorHandlers() is obsolete");
519 }
520
521 bool _dyld_present(void)
522 {
523 log_apis("_dyld_present()\n");
524
525 return true;
526 }
527
528 bool _dyld_launched_prebound(void)
529 {
530 halt("_dyld_launched_prebound() is obsolete");
531 }
532
533 bool _dyld_all_twolevel_modules_prebound(void)
534 {
535 halt("_dyld_all_twolevel_modules_prebound() is obsolete");
536 }
537
538 bool _dyld_bind_fully_image_containing_address(const void* address)
539 {
540 log_apis("_dyld_bind_fully_image_containing_address(%p)\n", address);
541
542 // in dyld3, everything is always fully bound
543 return true;
544 }
545
546 bool _dyld_image_containing_address(const void* address)
547 {
548 log_apis("_dyld_image_containing_address(%p)\n", address);
549
550 return (dyld_image_header_containing_address(address) != nullptr);
551 }
552
553 void _dyld_lookup_and_bind(const char* symbolName, void **address, NSModule* module)
554 {
555 log_apis("_dyld_lookup_and_bind(%s, %p, %p)\n", symbolName, address, module);
556
557 const mach_header* foundInImageAtLoadAddress;
558 if ( flatFindSymbol(symbolName, address, &foundInImageAtLoadAddress) ) {
559 *module = (NSModule)foundInImageAtLoadAddress;
560 return;
561 }
562
563 *address = 0;
564 *module = 0;
565 }
566
567 void _dyld_lookup_and_bind_with_hint(const char* symbolName, const char* libraryNameHint, void** address, NSModule* module)
568 {
569 log_apis("_dyld_lookup_and_bind_with_hint(%s, %s, %p, %p)\n", symbolName, libraryNameHint, address, module);
570
571 const mach_header* foundInImageAtLoadAddress;
572 if ( flatFindSymbol(symbolName, address, &foundInImageAtLoadAddress) ) {
573 *module = (NSModule)foundInImageAtLoadAddress;
574 return;
575 }
576
577 *address = 0;
578 *module = 0;
579 }
580
581
582 void _dyld_lookup_and_bind_fully(const char* symbolName, void** address, NSModule* module)
583 {
584 log_apis("_dyld_lookup_and_bind_fully(%s, %p, %p)\n", symbolName, address, module);
585
586 const mach_header* foundInImageAtLoadAddress;
587 if ( flatFindSymbol(symbolName, address, &foundInImageAtLoadAddress) ) {
588 *module = (NSModule)foundInImageAtLoadAddress;
589 return;
590 }
591
592 *address = 0;
593 *module = 0;
594 }
595
596 const struct mach_header* _dyld_get_image_header_containing_address(const void* address)
597 {
598 log_apis("_dyld_get_image_header_containing_address(%p)\n", address);
599
600 return dyld_image_header_containing_address(address);
601 }
602
603 #endif
604
605
606 } // namespace dyld3
607