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