1// Copyright 2011 The Chromium Authors 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "base/native_library.h" 6 7#include <dlfcn.h> 8#include <mach-o/getsect.h> 9 10#include "base/apple/scoped_cftyperef.h" 11#include "base/files/file_path.h" 12#include "base/files/file_util.h" 13#include "base/logging.h" 14#include "base/strings/strcat.h" 15#include "base/strings/string_piece.h" 16#include "base/strings/string_util.h" 17#include "base/strings/utf_string_conversions.h" 18#include "base/threading/thread_restrictions.h" 19 20namespace base { 21 22static NativeLibraryObjCStatus GetObjCStatusForImage( 23 const void* function_pointer) { 24 Dl_info info; 25 if (!dladdr(function_pointer, &info)) 26 return OBJC_UNKNOWN; 27 28 // See if the image contains an "ObjC image info" segment. This method 29 // of testing is used in _CFBundleGrokObjcImageInfoFromFile in 30 // CF-1153.18/CFBundle_Grok.c, around line 349. 31 // 32 // In 64-bit images, ObjC can be recognized in __DATA,__objc_imageinfo. 33 const auto* header = 34 reinterpret_cast<const struct mach_header_64*>(info.dli_fbase); 35 unsigned long size = 0; 36 getsectiondata(header, SEG_DATA, "__objc_imageinfo", &size); 37 if (size > 0) { 38 return OBJC_PRESENT; 39 } 40 // ....except when "SharedRegionEncodingV2" is on, it's in 41 // __DATA_CONST,__objc_image_info (see https://crbug.com/1220459#c16) 42 getsectiondata(header, "__DATA_CONST", "__objc_imageinfo", &size); 43 return size > 0 ? OBJC_PRESENT : OBJC_NOT_PRESENT; 44} 45 46std::string NativeLibraryLoadError::ToString() const { 47 return message; 48} 49 50NativeLibrary LoadNativeLibraryWithOptions(const FilePath& library_path, 51 const NativeLibraryOptions& options, 52 NativeLibraryLoadError* error) { 53 // dlopen() etc. open the file off disk. 54 if (library_path.Extension() == "dylib" || !DirectoryExists(library_path)) { 55 void* dylib = dlopen(library_path.value().c_str(), RTLD_LAZY); 56 if (!dylib) { 57 if (error) 58 error->message = dlerror(); 59 return nullptr; 60 } 61 NativeLibrary native_lib = new NativeLibraryStruct(); 62 native_lib->type = DYNAMIC_LIB; 63 native_lib->dylib = dylib; 64 native_lib->objc_status = OBJC_UNKNOWN; 65 return native_lib; 66 } 67 apple::ScopedCFTypeRef<CFURLRef> url(CFURLCreateFromFileSystemRepresentation( 68 kCFAllocatorDefault, (const UInt8*)library_path.value().c_str(), 69 checked_cast<CFIndex>(library_path.value().length()), true)); 70 if (!url) 71 return nullptr; 72 CFBundleRef bundle = CFBundleCreate(kCFAllocatorDefault, url.get()); 73 if (!bundle) 74 return nullptr; 75 76 NativeLibrary native_lib = new NativeLibraryStruct(); 77 native_lib->type = BUNDLE; 78 native_lib->bundle = bundle; 79 native_lib->objc_status = OBJC_UNKNOWN; 80 return native_lib; 81} 82 83void UnloadNativeLibrary(NativeLibrary library) { 84 if (library->objc_status == OBJC_NOT_PRESENT) { 85 if (library->type == BUNDLE) { 86 CFRelease(library->bundle); 87 } else { 88 dlclose(library->dylib); 89 } 90 } else { 91 VLOG(2) << "Not unloading NativeLibrary because it may contain an ObjC " 92 "segment. library->objc_status = " << library->objc_status; 93 // Deliberately do not CFRelease the bundle or dlclose the dylib because 94 // doing so can corrupt the ObjC runtime method caches. See 95 // http://crbug.com/172319 for details. 96 } 97 delete library; 98} 99 100void* GetFunctionPointerFromNativeLibrary(NativeLibrary library, 101 const char* name) { 102 void* function_pointer = nullptr; 103 104 // Get the function pointer using the right API for the type. 105 if (library->type == BUNDLE) { 106 apple::ScopedCFTypeRef<CFStringRef> symbol_name(CFStringCreateWithCString( 107 kCFAllocatorDefault, name, kCFStringEncodingUTF8)); 108 function_pointer = 109 CFBundleGetFunctionPointerForName(library->bundle, symbol_name.get()); 110 } else { 111 function_pointer = dlsym(library->dylib, name); 112 } 113 114 // If this library hasn't been tested for having ObjC, use the function 115 // pointer to look up the section information for the library. 116 if (function_pointer && library->objc_status == OBJC_UNKNOWN) 117 library->objc_status = GetObjCStatusForImage(function_pointer); 118 119 return function_pointer; 120} 121 122std::string GetNativeLibraryName(StringPiece name) { 123 DCHECK(IsStringASCII(name)); 124 return StrCat({"lib", name, ".dylib"}); 125} 126 127std::string GetLoadableModuleName(StringPiece name) { 128 DCHECK(IsStringASCII(name)); 129 return StrCat({name, ".so"}); 130} 131 132} // namespace base 133