OLD | NEW |
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "base/native_library.h" | 5 #include "base/native_library.h" |
6 | 6 |
7 #include <dlfcn.h> | 7 #include <dlfcn.h> |
| 8 #include <mach/task_info.h> |
| 9 #include <mach-o/dyld_images.h> |
| 10 #include <mach-o/getsect.h> |
8 | 11 |
9 #include "base/file_util.h" | 12 #include "base/file_util.h" |
10 #include "base/files/file_path.h" | 13 #include "base/files/file_path.h" |
| 14 #include "base/lazy_instance.h" |
| 15 #include "base/mac/mac_util.h" |
11 #include "base/mac/scoped_cftyperef.h" | 16 #include "base/mac/scoped_cftyperef.h" |
12 #include "base/string_util.h" | 17 #include "base/string_util.h" |
| 18 #include "base/synchronization/lock.h" |
13 #include "base/threading/thread_restrictions.h" | 19 #include "base/threading/thread_restrictions.h" |
14 #include "base/utf_string_conversions.h" | 20 #include "base/utf_string_conversions.h" |
15 | 21 |
| 22 extern "C" { |
| 23 |
| 24 // http://opensource.apple.com/source/dyld/dyld-195.5/include/mach-o/dyld_priv.h |
| 25 enum dyld_image_states |
| 26 { |
| 27 dyld_image_state_mapped = 10, // No batch notification for this |
| 28 dyld_image_state_dependents_mapped = 20, // Only batch notification for
this |
| 29 dyld_image_state_rebased = 30, |
| 30 dyld_image_state_bound = 40, |
| 31 dyld_image_state_dependents_initialized = 45, // Only single notification
for this |
| 32 dyld_image_state_initialized = 50, |
| 33 dyld_image_state_terminated = 60 // Only single notification for thi
s |
| 34 }; |
| 35 |
| 36 typedef const char* (*dyld_image_state_change_handler)( |
| 37 enum dyld_image_states state, uint32_t infoCount, |
| 38 const struct dyld_image_info info[]); |
| 39 |
| 40 void dyld_register_image_state_change_handler( |
| 41 enum dyld_image_states state, bool batch, |
| 42 dyld_image_state_change_handler handler); |
| 43 |
| 44 }; |
| 45 |
| 46 namespace { |
| 47 |
| 48 base::LazyInstance<base::Lock>::Leaky g_module_lock_ = |
| 49 LAZY_INSTANCE_INITIALIZER; |
| 50 base::LazyInstance<std::set<std::string> >::Leaky g_module_set_ = |
| 51 LAZY_INSTANCE_INITIALIZER; |
| 52 |
| 53 bool g_initial_registration = false; |
| 54 |
| 55 const char* Recorder(enum dyld_image_states state, |
| 56 uint32_t infoCount, |
| 57 const struct dyld_image_info info[]) { |
| 58 if (g_initial_registration) |
| 59 return NULL; |
| 60 |
| 61 for (uint32_t i = 0; i < infoCount; i++) { |
| 62 #if __LP64__ |
| 63 const struct mach_header_64* hdr = |
| 64 reinterpret_cast<const struct mach_header_64*>( |
| 65 info[i].imageLoadAddress); |
| 66 |
| 67 if (hdr->magic != MH_MAGIC_64 && hdr->magic != MH_CIGAM_64) |
| 68 continue; |
| 69 |
| 70 if (getsectbynamefromheader_64(hdr, SEG_DATA, "__objc_imageinfo")) { |
| 71 LOG(ERROR) << "64-bit Objective-C found"; |
| 72 LOG(ERROR) << "info[i].imageFilePath: " << info[i].imageFilePath; |
| 73 base::AutoLock pin(*g_module_lock_.Pointer()); |
| 74 g_module_set_.Pointer()->insert(info[i].imageFilePath); |
| 75 } |
| 76 #else |
| 77 const struct mach_header* hdr = |
| 78 reinterpret_cast<const struct mach_header*>( |
| 79 info[i].imageLoadAddress); |
| 80 |
| 81 if (hdr->magic != MH_MAGIC && hdr->magic != MH_CIGAM) |
| 82 continue; |
| 83 |
| 84 if (getsectbynamefromheader(hdr, SEG_OBJC, "__image_info")) { |
| 85 LOG(ERROR) << "32-bit Objective-C found"; |
| 86 LOG(ERROR) << "info[i].imageFilePath: " << info[i].imageFilePath; |
| 87 base::AutoLock pin(*g_module_lock_.Pointer()); |
| 88 g_module_set_.Pointer()->insert(info[i].imageFilePath); |
| 89 } |
| 90 #endif |
| 91 } |
| 92 return NULL; |
| 93 } |
| 94 |
| 95 void Initialize() { |
| 96 static bool initialized = false; |
| 97 if (!initialized) { |
| 98 initialized = true; |
| 99 g_initial_registration = true; |
| 100 dyld_register_image_state_change_handler(dyld_image_state_mapped, 0 /* \ |
| 101 batch */, &Recorder); |
| 102 g_initial_registration = false; |
| 103 } |
| 104 } |
| 105 |
| 106 } // namespace |
| 107 |
16 namespace base { | 108 namespace base { |
17 | 109 |
18 // static | 110 // static |
19 NativeLibrary LoadNativeLibrary(const base::FilePath& library_path, | 111 NativeLibrary LoadNativeLibrary(const base::FilePath& library_path, |
20 std::string* error) { | 112 std::string* error) { |
| 113 Initialize(); |
| 114 |
21 // dlopen() etc. open the file off disk. | 115 // dlopen() etc. open the file off disk. |
22 if (library_path.Extension() == "dylib" || | 116 if (library_path.Extension() == "dylib" || |
23 !file_util::DirectoryExists(library_path)) { | 117 !file_util::DirectoryExists(library_path)) { |
24 void* dylib = dlopen(library_path.value().c_str(), RTLD_LAZY); | 118 void* dylib = dlopen(library_path.value().c_str(), RTLD_LAZY); |
25 if (!dylib) | 119 if (!dylib) |
26 return NULL; | 120 return NULL; |
27 NativeLibrary native_lib = new NativeLibraryStruct(); | 121 NativeLibrary native_lib = new NativeLibraryStruct(); |
28 native_lib->type = DYNAMIC_LIB; | 122 native_lib->type = DYNAMIC_LIB; |
29 native_lib->dylib = dylib; | 123 native_lib->dylib = dylib; |
| 124 native_lib->image_path = library_path; |
30 return native_lib; | 125 return native_lib; |
31 } | 126 } |
32 base::mac::ScopedCFTypeRef<CFURLRef> url( | 127 base::mac::ScopedCFTypeRef<CFURLRef> url( |
33 CFURLCreateFromFileSystemRepresentation( | 128 CFURLCreateFromFileSystemRepresentation( |
34 kCFAllocatorDefault, | 129 kCFAllocatorDefault, |
35 (const UInt8*)library_path.value().c_str(), | 130 (const UInt8*)library_path.value().c_str(), |
36 library_path.value().length(), | 131 library_path.value().length(), |
37 true)); | 132 true)); |
38 if (!url) | 133 if (!url) |
39 return NULL; | 134 return NULL; |
40 CFBundleRef bundle = CFBundleCreate(kCFAllocatorDefault, url.get()); | 135 CFBundleRef bundle = CFBundleCreate(kCFAllocatorDefault, url.get()); |
41 if (!bundle) | 136 if (!bundle) |
42 return NULL; | 137 return NULL; |
43 | 138 |
44 NativeLibrary native_lib = new NativeLibraryStruct(); | 139 NativeLibrary native_lib = new NativeLibraryStruct(); |
45 native_lib->type = BUNDLE; | 140 native_lib->type = BUNDLE; |
46 native_lib->bundle = bundle; | 141 native_lib->bundle = bundle; |
47 native_lib->bundle_resource_ref = CFBundleOpenBundleResourceMap(bundle); | 142 native_lib->bundle_resource_ref = CFBundleOpenBundleResourceMap(bundle); |
| 143 |
| 144 base::mac::ScopedCFTypeRef<CFURLRef> executable_url( |
| 145 CFBundleCopyExecutableURL(bundle)); |
| 146 NSURL* executable_url_ns = base::mac::CFToNSCast(executable_url); |
| 147 native_lib->image_path = |
| 148 base::FilePath([[executable_url_ns path] fileSystemRepresentation]); |
| 149 |
48 return native_lib; | 150 return native_lib; |
49 } | 151 } |
50 | 152 |
51 // static | 153 // static |
52 void UnloadNativeLibrary(NativeLibrary library) { | 154 void UnloadNativeLibrary(NativeLibrary library) { |
53 if (library->type == BUNDLE) { | 155 bool unload = true; |
54 CFBundleCloseBundleResourceMap(library->bundle, | 156 { |
55 library->bundle_resource_ref); | 157 base::AutoLock pin(*g_module_lock_.Pointer()); |
56 CFRelease(library->bundle); | 158 unload = !g_module_set_.Pointer()->count(library->image_path.value().c_str()
); |
57 } else { | 159 } |
58 dlclose(library->dylib); | 160 if (unload) { |
| 161 if (library->type == BUNDLE) { |
| 162 CFBundleCloseBundleResourceMap(library->bundle, |
| 163 library->bundle_resource_ref); |
| 164 CFRelease(library->bundle); |
| 165 } else { |
| 166 dlclose(library->dylib); |
| 167 } |
59 } | 168 } |
60 delete library; | 169 delete library; |
61 } | 170 } |
62 | 171 |
63 // static | 172 // static |
64 void* GetFunctionPointerFromNativeLibrary(NativeLibrary library, | 173 void* GetFunctionPointerFromNativeLibrary(NativeLibrary library, |
65 const char* name) { | 174 const char* name) { |
66 if (library->type == BUNDLE) { | 175 if (library->type == BUNDLE) { |
67 base::mac::ScopedCFTypeRef<CFStringRef> symbol_name( | 176 base::mac::ScopedCFTypeRef<CFStringRef> symbol_name( |
68 CFStringCreateWithCString(kCFAllocatorDefault, name, | 177 CFStringCreateWithCString(kCFAllocatorDefault, name, |
69 kCFStringEncodingUTF8)); | 178 kCFStringEncodingUTF8)); |
70 return CFBundleGetFunctionPointerForName(library->bundle, symbol_name); | 179 return CFBundleGetFunctionPointerForName(library->bundle, symbol_name); |
71 } | 180 } |
72 return dlsym(library->dylib, name); | 181 return dlsym(library->dylib, name); |
73 } | 182 } |
74 | 183 |
75 // static | 184 // static |
76 string16 GetNativeLibraryName(const string16& name) { | 185 string16 GetNativeLibraryName(const string16& name) { |
77 return name + ASCIIToUTF16(".dylib"); | 186 return name + ASCIIToUTF16(".dylib"); |
78 } | 187 } |
79 | 188 |
80 } // namespace base | 189 } // namespace base |
OLD | NEW |