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