1// Copyright (c) 2011 The Chromium Authors. All rights reserved. 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/file_util.h" 11#include "base/files/file_path.h" 12#include "base/logging.h" 13#include "base/mac/scoped_cftyperef.h" 14#include "base/strings/string_util.h" 15#include "base/strings/utf_string_conversions.h" 16#include "base/threading/thread_restrictions.h" 17 18namespace base { 19 20static NativeLibraryObjCStatus GetObjCStatusForImage( 21 const void* function_pointer) { 22 Dl_info info; 23 if (!dladdr(function_pointer, &info)) 24 return OBJC_UNKNOWN; 25 26 // See if the the image contains an "ObjC image info" segment. This method 27 // of testing is used in _CFBundleGrokObjcImageInfoFromFile in 28 // CF-744/CFBundle.c, around lines 2447-2474. 29 // 30 // In 32-bit images, ObjC can be recognized in __OBJC,__image_info, whereas 31 // in 64-bit, the data is in __DATA,__objc_imageinfo. 32#if __LP64__ 33 const section_64* section = getsectbynamefromheader_64( 34 reinterpret_cast<const struct mach_header_64*>(info.dli_fbase), 35 SEG_DATA, "__objc_imageinfo"); 36#else 37 const section* section = getsectbynamefromheader( 38 reinterpret_cast<const struct mach_header*>(info.dli_fbase), 39 SEG_OBJC, "__image_info"); 40#endif 41 return section == NULL ? OBJC_NOT_PRESENT : OBJC_PRESENT; 42} 43 44// static 45NativeLibrary LoadNativeLibrary(const base::FilePath& library_path, 46 std::string* error) { 47 // dlopen() etc. open the file off disk. 48 if (library_path.Extension() == "dylib" || !DirectoryExists(library_path)) { 49 void* dylib = dlopen(library_path.value().c_str(), RTLD_LAZY); 50 if (!dylib) 51 return NULL; 52 NativeLibrary native_lib = new NativeLibraryStruct(); 53 native_lib->type = DYNAMIC_LIB; 54 native_lib->dylib = dylib; 55 native_lib->objc_status = OBJC_UNKNOWN; 56 return native_lib; 57 } 58 base::ScopedCFTypeRef<CFURLRef> url(CFURLCreateFromFileSystemRepresentation( 59 kCFAllocatorDefault, 60 (const UInt8*)library_path.value().c_str(), 61 library_path.value().length(), 62 true)); 63 if (!url) 64 return NULL; 65 CFBundleRef bundle = CFBundleCreate(kCFAllocatorDefault, url.get()); 66 if (!bundle) 67 return NULL; 68 69 NativeLibrary native_lib = new NativeLibraryStruct(); 70 native_lib->type = BUNDLE; 71 native_lib->bundle = bundle; 72 native_lib->bundle_resource_ref = CFBundleOpenBundleResourceMap(bundle); 73 native_lib->objc_status = OBJC_UNKNOWN; 74 return native_lib; 75} 76 77// static 78void UnloadNativeLibrary(NativeLibrary library) { 79 if (library->objc_status == OBJC_NOT_PRESENT) { 80 if (library->type == BUNDLE) { 81 CFBundleCloseBundleResourceMap(library->bundle, 82 library->bundle_resource_ref); 83 CFRelease(library->bundle); 84 } else { 85 dlclose(library->dylib); 86 } 87 } else { 88 VLOG(2) << "Not unloading NativeLibrary because it may contain an ObjC " 89 "segment. library->objc_status = " << library->objc_status; 90 // Deliberately do not CFRelease the bundle or dlclose the dylib because 91 // doing so can corrupt the ObjC runtime method caches. See 92 // http://crbug.com/172319 for details. 93 } 94 delete library; 95} 96 97// static 98void* GetFunctionPointerFromNativeLibrary(NativeLibrary library, 99 const char* name) { 100 void* function_pointer = NULL; 101 102 // Get the function pointer using the right API for the type. 103 if (library->type == BUNDLE) { 104 base::ScopedCFTypeRef<CFStringRef> symbol_name(CFStringCreateWithCString( 105 kCFAllocatorDefault, name, kCFStringEncodingUTF8)); 106 function_pointer = CFBundleGetFunctionPointerForName(library->bundle, 107 symbol_name); 108 } else { 109 function_pointer = dlsym(library->dylib, name); 110 } 111 112 // If this library hasn't been tested for having ObjC, use the function 113 // pointer to look up the section information for the library. 114 if (function_pointer && library->objc_status == OBJC_UNKNOWN) 115 library->objc_status = GetObjCStatusForImage(function_pointer); 116 117 return function_pointer; 118} 119 120// static 121string16 GetNativeLibraryName(const string16& name) { 122 return name + ASCIIToUTF16(".dylib"); 123} 124 125} // namespace base 126