dyld-832.7.1.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 TARGET_OS_OSX
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 ( dyld3::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, false) != 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(), false, 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->builtForPlatform(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 // <rdar://problem/59265987> allow flat lookup to find "_memcpy" even though it is not implemented as that name in any dylib
347 MachOLoaded::DependentToMachOLoaded finder = ^(const MachOLoaded* mh, uint32_t depIndex) {
348 return gAllImages.findDependent(mh, depIndex);
349 };
350
351 __block bool result = false;
352 gAllImages.forEachImage(^(const LoadedImage& loadedImage, bool& stop) {
353 bool resultPointsToInstructions = false;
354 if ( loadedImage.loadedAddress()->hasExportedSymbol(symbolName, finder, symbolAddress, &resultPointsToInstructions) ) {
355 *foundInImageAtLoadAddress = loadedImage.loadedAddress();
356 stop = true;
357 result = true;
358 }
359 });
360 return result;
361 }
362
363 bool NSIsSymbolNameDefined(const char* symbolName)
364 {
365 log_apis("NSIsSymbolNameDefined(%s)\n", symbolName);
366
367 const mach_header* foundInImageAtLoadAddress;
368 void* address;
369 return flatFindSymbol(symbolName, &address, &foundInImageAtLoadAddress);
370 }
371
372 bool NSIsSymbolNameDefinedWithHint(const char* symbolName, const char* libraryNameHint)
373 {
374 log_apis("NSIsSymbolNameDefinedWithHint(%s, %s)\n", symbolName, libraryNameHint);
375
376 const mach_header* foundInImageAtLoadAddress;
377 void* address;
378 return flatFindSymbol(symbolName, &address, &foundInImageAtLoadAddress);
379 }
380
381 bool NSIsSymbolNameDefinedInImage(const struct mach_header* mh, const char* symbolName)
382 {
383 log_apis("NSIsSymbolNameDefinedInImage(%p, %s)\n", mh, symbolName);
384
385 void* addr;
386 bool resultPointsToInstructions = false;
387 return ((MachOLoaded*)mh)->hasExportedSymbol(symbolName, nullptr, &addr, &resultPointsToInstructions);
388 }
389
390 NSSymbol NSLookupAndBindSymbol(const char* symbolName)
391 {
392 log_apis("NSLookupAndBindSymbol(%s)\n", symbolName);
393
394 const mach_header* foundInImageAtLoadAddress;
395 void* symbolAddress;
396 if ( flatFindSymbol(symbolName, &symbolAddress, &foundInImageAtLoadAddress) ) {
397 return (NSSymbol)symbolAddress;
398 }
399 return nullptr;
400 }
401
402 NSSymbol NSLookupAndBindSymbolWithHint(const char* symbolName, const char* libraryNameHint)
403 {
404 log_apis("NSLookupAndBindSymbolWithHint(%s, %s)\n", symbolName, libraryNameHint);
405
406 const mach_header* foundInImageAtLoadAddress;
407 void* symbolAddress;
408 if ( flatFindSymbol(symbolName, &symbolAddress, &foundInImageAtLoadAddress) ) {
409 return (NSSymbol)symbolAddress;
410 }
411 return nullptr;
412 }
413
414 NSSymbol NSLookupSymbolInModule(NSModule module, const char* symbolName)
415 {
416 log_apis("NSLookupSymbolInModule(%p. %s)\n", module, symbolName);
417
418 const MachOLoaded* mh = (const MachOLoaded*)module;
419 void* addr;
420 bool resultPointsToInstructions = false;
421 if ( mh->hasExportedSymbol(symbolName, nullptr, &addr, &resultPointsToInstructions) ) {
422 return (NSSymbol)addr;
423 }
424 return nullptr;
425 }
426
427 NSSymbol NSLookupSymbolInImage(const mach_header* mh, const char* symbolName, uint32_t options)
428 {
429 log_apis("NSLookupSymbolInImage(%p, \"%s\", 0x%08X)\n", mh, symbolName, options);
430
431 void* addr;
432 bool resultPointsToInstructions = false;
433 if ( ((MachOLoaded*)mh)->hasExportedSymbol(symbolName, nullptr, &addr, &resultPointsToInstructions) ) {
434 log_apis(" NSLookupSymbolInImage() => %p\n", addr);
435 return (NSSymbol)addr;
436 }
437 if ( options & NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR ) {
438 log_apis(" NSLookupSymbolInImage() => NULL\n");
439 return nullptr;
440 }
441 // FIXME: abort();
442 return nullptr;
443 }
444
445 const char* NSNameOfSymbol(NSSymbol symbol)
446 {
447 halt("NSNameOfSymbol() is obsolete");
448 }
449
450 void* NSAddressOfSymbol(NSSymbol symbol)
451 {
452 log_apis("NSAddressOfSymbol(%p)\n", symbol);
453
454 // in dyld 1.0, NSSymbol was a pointer to the nlist entry in the symbol table
455 return (void*)symbol;
456 }
457
458 NSModule NSModuleForSymbol(NSSymbol symbol)
459 {
460 log_apis("NSModuleForSymbol(%p)\n", symbol);
461
462 __block NSModule result = nullptr;
463 gAllImages.infoForImageMappedAt(symbol, ^(const LoadedImage& foundImage, uint8_t permissions) {
464 result = (NSModule)foundImage.loadedAddress();
465 });
466
467 return result;
468 }
469
470 void NSLinkEditError(NSLinkEditErrors *c, int *errorNumber, const char** fileName, const char** errorString)
471 {
472 log_apis("NSLinkEditError(%p, %p, %p, %p)\n", c, errorNumber, fileName, errorString);
473 *c = NSLinkEditOtherError;
474 *errorNumber = 0;
475 *fileName = NULL;
476 *errorString = NULL;
477 }
478
479 bool NSAddLibrary(const char* pathName)
480 {
481 log_apis("NSAddLibrary(%s)\n", pathName);
482
483 void* callerAddress = __builtin_return_address(1); // note layers: 1: real client, 0: libSystem glue
484 return ( dlopen_internal(pathName, 0, callerAddress) != nullptr);
485 }
486
487 bool NSAddLibraryWithSearching(const char* pathName)
488 {
489 log_apis("NSAddLibraryWithSearching(%s)\n", pathName);
490
491 void* callerAddress = __builtin_return_address(1); // note layers: 1: real client, 0: libSystem glue
492 return ( dlopen_internal(pathName, 0, callerAddress) != nullptr);
493 }
494
495 const mach_header* NSAddImage(const char* imageName, uint32_t options)
496 {
497 log_apis("NSAddImage(\"%s\", 0x%08X)\n", imageName, options);
498
499 // Note: this is a quick and dirty implementation that just uses dlopen() and ignores some option flags
500 uint32_t dloptions = 0;
501 if ( (options & NSADDIMAGE_OPTION_RETURN_ONLY_IF_LOADED) != 0 )
502 dloptions |= RTLD_NOLOAD;
503
504 void* callerAddress = __builtin_return_address(1); // note layers: 1: real client, 0: libSystem glue
505 void* h = dlopen_internal(imageName, dloptions, callerAddress);
506 if ( h != nullptr ) {
507 const MachOLoaded* mh;
508 bool dontContinue;
509 parseDlHandle(h, &mh, &dontContinue);
510 return mh;
511 }
512
513 if ( (options & (NSADDIMAGE_OPTION_RETURN_ON_ERROR|NSADDIMAGE_OPTION_RETURN_ONLY_IF_LOADED)) == 0 ) {
514 halt("NSAddImage() image not found");
515 }
516 return nullptr;
517 }
518
519 void NSInstallLinkEditErrorHandlers(const NSLinkEditErrorHandlers *handlers)
520 {
521 halt("NSInstallLinkEditErrorHandlers() is obsolete");
522 }
523
524 bool _dyld_present(void)
525 {
526 log_apis("_dyld_present()\n");
527
528 return true;
529 }
530
531 bool _dyld_launched_prebound(void)
532 {
533 halt("_dyld_launched_prebound() is obsolete");
534 }
535
536 bool _dyld_all_twolevel_modules_prebound(void)
537 {
538 halt("_dyld_all_twolevel_modules_prebound() is obsolete");
539 }
540
541 bool _dyld_bind_fully_image_containing_address(const void* address)
542 {
543 log_apis("_dyld_bind_fully_image_containing_address(%p)\n", address);
544
545 // in dyld3, everything is always fully bound
546 return true;
547 }
548
549 bool _dyld_image_containing_address(const void* address)
550 {
551 log_apis("_dyld_image_containing_address(%p)\n", address);
552
553 return (dyld_image_header_containing_address(address) != nullptr);
554 }
555
556 void _dyld_lookup_and_bind(const char* symbolName, void **address, NSModule* module)
557 {
558 log_apis("_dyld_lookup_and_bind(%s, %p, %p)\n", symbolName, address, module);
559
560 const mach_header* foundInImageAtLoadAddress;
561 if ( flatFindSymbol(symbolName, address, &foundInImageAtLoadAddress) ) {
562 *module = (NSModule)foundInImageAtLoadAddress;
563 return;
564 }
565
566 *address = 0;
567 *module = 0;
568 }
569
570 void _dyld_lookup_and_bind_with_hint(const char* symbolName, const char* libraryNameHint, void** address, NSModule* module)
571 {
572 log_apis("_dyld_lookup_and_bind_with_hint(%s, %s, %p, %p)\n", symbolName, libraryNameHint, address, module);
573
574 const mach_header* foundInImageAtLoadAddress;
575 if ( flatFindSymbol(symbolName, address, &foundInImageAtLoadAddress) ) {
576 *module = (NSModule)foundInImageAtLoadAddress;
577 return;
578 }
579
580 *address = 0;
581 *module = 0;
582 }
583
584
585 void _dyld_lookup_and_bind_fully(const char* symbolName, void** address, NSModule* module)
586 {
587 log_apis("_dyld_lookup_and_bind_fully(%s, %p, %p)\n", symbolName, address, module);
588
589 const mach_header* foundInImageAtLoadAddress;
590 if ( flatFindSymbol(symbolName, address, &foundInImageAtLoadAddress) ) {
591 *module = (NSModule)foundInImageAtLoadAddress;
592 return;
593 }
594
595 *address = 0;
596 *module = 0;
597 }
598
599 const struct mach_header* _dyld_get_image_header_containing_address(const void* address)
600 {
601 log_apis("_dyld_get_image_header_containing_address(%p)\n", address);
602
603 return dyld_image_header_containing_address(address);
604 }
605
606 #endif
607
608
609 } // namespace dyld3
610