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 131 132
|
// Copyright 2011 The Chromium Authors
// 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/apple/scoped_cftyperef.h"
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/logging.h"
#include "base/strings/strcat.h"
#include "base/strings/string_piece.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 image contains an "ObjC image info" segment. This method
// of testing is used in _CFBundleGrokObjcImageInfoFromFile in
// CF-1153.18/CFBundle_Grok.c, around line 349.
//
// In 64-bit images, ObjC can be recognized in __DATA,__objc_imageinfo.
const auto* header =
reinterpret_cast<const struct mach_header_64*>(info.dli_fbase);
unsigned long size = 0;
getsectiondata(header, SEG_DATA, "__objc_imageinfo", &size);
if (size > 0) {
return OBJC_PRESENT;
}
// ....except when "SharedRegionEncodingV2" is on, it's in
// __DATA_CONST,__objc_image_info (see https://crbug.com/1220459#c16)
getsectiondata(header, "__DATA_CONST", "__objc_imageinfo", &size);
return size > 0 ? OBJC_PRESENT : OBJC_NOT_PRESENT;
}
std::string NativeLibraryLoadError::ToString() const {
return message;
}
NativeLibrary LoadNativeLibraryWithOptions(const FilePath& library_path,
const NativeLibraryOptions& options,
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) {
if (error)
error->message = dlerror();
return nullptr;
}
NativeLibrary native_lib = new NativeLibraryStruct();
native_lib->type = DYNAMIC_LIB;
native_lib->dylib = dylib;
native_lib->objc_status = OBJC_UNKNOWN;
return native_lib;
}
apple::ScopedCFTypeRef<CFURLRef> url(CFURLCreateFromFileSystemRepresentation(
kCFAllocatorDefault, (const UInt8*)library_path.value().c_str(),
checked_cast<CFIndex>(library_path.value().length()), true));
if (!url)
return nullptr;
CFBundleRef bundle = CFBundleCreate(kCFAllocatorDefault, url.get());
if (!bundle)
return nullptr;
NativeLibrary native_lib = new NativeLibraryStruct();
native_lib->type = BUNDLE;
native_lib->bundle = bundle;
native_lib->objc_status = OBJC_UNKNOWN;
return native_lib;
}
void UnloadNativeLibrary(NativeLibrary library) {
if (library->objc_status == OBJC_NOT_PRESENT) {
if (library->type == BUNDLE) {
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;
}
void* GetFunctionPointerFromNativeLibrary(NativeLibrary library,
const char* name) {
void* function_pointer = nullptr;
// Get the function pointer using the right API for the type.
if (library->type == BUNDLE) {
apple::ScopedCFTypeRef<CFStringRef> symbol_name(CFStringCreateWithCString(
kCFAllocatorDefault, name, kCFStringEncodingUTF8));
function_pointer =
CFBundleGetFunctionPointerForName(library->bundle, symbol_name.get());
} 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;
}
std::string GetNativeLibraryName(StringPiece name) {
DCHECK(IsStringASCII(name));
return StrCat({"lib", name, ".dylib"});
}
std::string GetLoadableModuleName(StringPiece name) {
DCHECK(IsStringASCII(name));
return StrCat({name, ".so"});
}
} // namespace base
|