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