blob: 4a0947561c892953dc54bc0b2cc3df73ca19acb2 [file] [log] [blame]
[email protected]84479322011-04-18 22:06:221// Copyright (c) 2011 The Chromium Authors. All rights reserved.
[email protected]f38e25f2009-04-21 00:56:072// 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
[email protected]108c2a12009-06-05 22:18:097#include <dlfcn.h>
[email protected]5625f3cf2013-03-15 12:10:588#include <mach-o/getsect.h>
[email protected]f38e25f2009-04-21 00:56:079
[email protected]108c2a12009-06-05 22:18:0910#include "base/file_util.h"
[email protected]57999812013-02-24 05:40:5211#include "base/files/file_path.h"
[email protected]5625f3cf2013-03-15 12:10:5812#include "base/logging.h"
[email protected]df0ca6c82010-10-17 04:09:0613#include "base/mac/scoped_cftyperef.h"
[email protected]108c2a12009-06-05 22:18:0914#include "base/string_util.h"
[email protected]3d169832011-01-02 20:10:0515#include "base/threading/thread_restrictions.h"
[email protected]81e34d82010-08-19 18:36:2516#include "base/utf_string_conversions.h"
[email protected]f38e25f2009-04-21 00:56:0717
18namespace base {
19
[email protected]5625f3cf2013-03-15 12:10:5820static 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
[email protected]f38e25f2009-04-21 00:56:0744// static
[email protected]aaa6df42013-02-17 19:36:0345NativeLibrary LoadNativeLibrary(const base::FilePath& library_path,
[email protected]84479322011-04-18 22:06:2246 std::string* error) {
[email protected]be130682010-11-12 21:53:1647 // dlopen() etc. open the file off disk.
[email protected]108c2a12009-06-05 22:18:0948 if (library_path.Extension() == "dylib" ||
49 !file_util::DirectoryExists(library_path)) {
50 void* dylib = dlopen(library_path.value().c_str(), RTLD_LAZY);
51 if (!dylib)
52 return NULL;
53 NativeLibrary native_lib = new NativeLibraryStruct();
54 native_lib->type = DYNAMIC_LIB;
55 native_lib->dylib = dylib;
[email protected]5625f3cf2013-03-15 12:10:5856 native_lib->objc_status = OBJC_UNKNOWN;
[email protected]108c2a12009-06-05 22:18:0957 return native_lib;
58 }
[email protected]df0ca6c82010-10-17 04:09:0659 base::mac::ScopedCFTypeRef<CFURLRef> url(
60 CFURLCreateFromFileSystemRepresentation(
61 kCFAllocatorDefault,
62 (const UInt8*)library_path.value().c_str(),
63 library_path.value().length(),
64 true));
[email protected]f38e25f2009-04-21 00:56:0765 if (!url)
66 return NULL;
[email protected]108c2a12009-06-05 22:18:0967 CFBundleRef bundle = CFBundleCreate(kCFAllocatorDefault, url.get());
68 if (!bundle)
69 return NULL;
[email protected]f38e25f2009-04-21 00:56:0770
[email protected]108c2a12009-06-05 22:18:0971 NativeLibrary native_lib = new NativeLibraryStruct();
72 native_lib->type = BUNDLE;
73 native_lib->bundle = bundle;
[email protected]d8921c432010-01-28 16:08:0974 native_lib->bundle_resource_ref = CFBundleOpenBundleResourceMap(bundle);
[email protected]5625f3cf2013-03-15 12:10:5875 native_lib->objc_status = OBJC_UNKNOWN;
[email protected]108c2a12009-06-05 22:18:0976 return native_lib;
[email protected]f38e25f2009-04-21 00:56:0777}
78
79// static
80void UnloadNativeLibrary(NativeLibrary library) {
[email protected]5625f3cf2013-03-15 12:10:5881 if (library->objc_status == OBJC_NOT_PRESENT) {
82 if (library->type == BUNDLE) {
83 CFBundleCloseBundleResourceMap(library->bundle,
84 library->bundle_resource_ref);
85 CFRelease(library->bundle);
86 } else {
87 dlclose(library->dylib);
88 }
[email protected]d8921c432010-01-28 16:08:0989 } else {
[email protected]5625f3cf2013-03-15 12:10:5890 VLOG(2) << "Not unloading NativeLibrary because it may contain an ObjC "
91 "segment. library->objc_status = " << library->objc_status;
92 // Deliberately do not CFRelease the bundle or dlclose the dylib because
93 // doing so can corrupt the ObjC runtime method caches. See
94 // http://crbug.com/172319 for details.
[email protected]d8921c432010-01-28 16:08:0995 }
[email protected]108c2a12009-06-05 22:18:0996 delete library;
[email protected]f38e25f2009-04-21 00:56:0797}
98
99// static
100void* GetFunctionPointerFromNativeLibrary(NativeLibrary library,
[email protected]108c2a12009-06-05 22:18:09101 const char* name) {
[email protected]5625f3cf2013-03-15 12:10:58102 void* function_pointer = NULL;
103
104 // Get the function pointer using the right API for the type.
[email protected]b7efd7692009-12-15 22:34:09105 if (library->type == BUNDLE) {
[email protected]df0ca6c82010-10-17 04:09:06106 base::mac::ScopedCFTypeRef<CFStringRef> symbol_name(
[email protected]108c2a12009-06-05 22:18:09107 CFStringCreateWithCString(kCFAllocatorDefault, name,
108 kCFStringEncodingUTF8));
[email protected]5625f3cf2013-03-15 12:10:58109 function_pointer = CFBundleGetFunctionPointerForName(library->bundle,
110 symbol_name);
111 } else {
112 function_pointer = dlsym(library->dylib, name);
[email protected]b7efd7692009-12-15 22:34:09113 }
[email protected]5625f3cf2013-03-15 12:10:58114
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;
[email protected]108c2a12009-06-05 22:18:09121}
122
123// static
124string16 GetNativeLibraryName(const string16& name) {
125 return name + ASCIIToUTF16(".dylib");
[email protected]f38e25f2009-04-21 00:56:07126}
127
128} // namespace base