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