Index: base/native_library_mac.mm |
diff --git a/base/native_library_mac.mm b/base/native_library_mac.mm |
index eec586b863588d9856cc0221da1e73973e10e8de..58fc3be93ba220a6394ce3fc4519eae0333f4365 100644 |
--- a/base/native_library_mac.mm |
+++ b/base/native_library_mac.mm |
@@ -5,19 +5,113 @@ |
#include "base/native_library.h" |
#include <dlfcn.h> |
+#include <mach/task_info.h> |
+#include <mach-o/dyld_images.h> |
+#include <mach-o/getsect.h> |
#include "base/file_util.h" |
#include "base/files/file_path.h" |
+#include "base/lazy_instance.h" |
+#include "base/mac/mac_util.h" |
#include "base/mac/scoped_cftyperef.h" |
#include "base/string_util.h" |
+#include "base/synchronization/lock.h" |
#include "base/threading/thread_restrictions.h" |
#include "base/utf_string_conversions.h" |
+extern "C" { |
+ |
+// http://opensource.apple.com/source/dyld/dyld-195.5/include/mach-o/dyld_priv.h |
+enum dyld_image_states |
+{ |
+ dyld_image_state_mapped = 10, // No batch notification for this |
+ dyld_image_state_dependents_mapped = 20, // Only batch notification for this |
+ dyld_image_state_rebased = 30, |
+ dyld_image_state_bound = 40, |
+ dyld_image_state_dependents_initialized = 45, // Only single notification for this |
+ dyld_image_state_initialized = 50, |
+ dyld_image_state_terminated = 60 // Only single notification for this |
+}; |
+ |
+typedef const char* (*dyld_image_state_change_handler)( |
+ enum dyld_image_states state, uint32_t infoCount, |
+ const struct dyld_image_info info[]); |
+ |
+void dyld_register_image_state_change_handler( |
+ enum dyld_image_states state, bool batch, |
+ dyld_image_state_change_handler handler); |
+ |
+}; |
+ |
+namespace { |
+ |
+base::LazyInstance<base::Lock>::Leaky g_module_lock_ = |
+ LAZY_INSTANCE_INITIALIZER; |
+base::LazyInstance<std::set<std::string> >::Leaky g_module_set_ = |
+ LAZY_INSTANCE_INITIALIZER; |
+ |
+bool g_initial_registration = false; |
+ |
+const char* Recorder(enum dyld_image_states state, |
+ uint32_t infoCount, |
+ const struct dyld_image_info info[]) { |
+ if (g_initial_registration) |
+ return NULL; |
+ |
+ for (uint32_t i = 0; i < infoCount; i++) { |
+#if __LP64__ |
+ const struct mach_header_64* hdr = |
+ reinterpret_cast<const struct mach_header_64*>( |
+ info[i].imageLoadAddress); |
+ |
+ if (hdr->magic != MH_MAGIC_64 && hdr->magic != MH_CIGAM_64) |
+ continue; |
+ |
+ if (getsectbynamefromheader_64(hdr, SEG_DATA, "__objc_imageinfo")) { |
+ LOG(ERROR) << "64-bit Objective-C found"; |
+ LOG(ERROR) << "info[i].imageFilePath: " << info[i].imageFilePath; |
+ base::AutoLock pin(*g_module_lock_.Pointer()); |
+ g_module_set_.Pointer()->insert(info[i].imageFilePath); |
+ } |
+#else |
+ const struct mach_header* hdr = |
+ reinterpret_cast<const struct mach_header*>( |
+ info[i].imageLoadAddress); |
+ |
+ if (hdr->magic != MH_MAGIC && hdr->magic != MH_CIGAM) |
+ continue; |
+ |
+ if (getsectbynamefromheader(hdr, SEG_OBJC, "__image_info")) { |
+ LOG(ERROR) << "32-bit Objective-C found"; |
+ LOG(ERROR) << "info[i].imageFilePath: " << info[i].imageFilePath; |
+ base::AutoLock pin(*g_module_lock_.Pointer()); |
+ g_module_set_.Pointer()->insert(info[i].imageFilePath); |
+ } |
+#endif |
+ } |
+ return NULL; |
+} |
+ |
+void Initialize() { |
+ static bool initialized = false; |
+ if (!initialized) { |
+ initialized = true; |
+ g_initial_registration = true; |
+ dyld_register_image_state_change_handler(dyld_image_state_mapped, 0 /* \ |
+batch */, &Recorder); |
+ g_initial_registration = false; |
+ } |
+} |
+ |
+} // namespace |
+ |
namespace base { |
// static |
NativeLibrary LoadNativeLibrary(const base::FilePath& library_path, |
std::string* error) { |
+ Initialize(); |
+ |
// dlopen() etc. open the file off disk. |
if (library_path.Extension() == "dylib" || |
!file_util::DirectoryExists(library_path)) { |
@@ -27,6 +121,7 @@ NativeLibrary LoadNativeLibrary(const base::FilePath& library_path, |
NativeLibrary native_lib = new NativeLibraryStruct(); |
native_lib->type = DYNAMIC_LIB; |
native_lib->dylib = dylib; |
+ native_lib->image_path = library_path; |
return native_lib; |
} |
base::mac::ScopedCFTypeRef<CFURLRef> url( |
@@ -45,17 +140,31 @@ NativeLibrary LoadNativeLibrary(const base::FilePath& library_path, |
native_lib->type = BUNDLE; |
native_lib->bundle = bundle; |
native_lib->bundle_resource_ref = CFBundleOpenBundleResourceMap(bundle); |
+ |
+ base::mac::ScopedCFTypeRef<CFURLRef> executable_url( |
+ CFBundleCopyExecutableURL(bundle)); |
+ NSURL* executable_url_ns = base::mac::CFToNSCast(executable_url); |
+ native_lib->image_path = |
+ base::FilePath([[executable_url_ns path] fileSystemRepresentation]); |
+ |
return native_lib; |
} |
// static |
void UnloadNativeLibrary(NativeLibrary library) { |
- if (library->type == BUNDLE) { |
- CFBundleCloseBundleResourceMap(library->bundle, |
- library->bundle_resource_ref); |
- CFRelease(library->bundle); |
- } else { |
- dlclose(library->dylib); |
+ bool unload = true; |
+ { |
+ base::AutoLock pin(*g_module_lock_.Pointer()); |
+ unload = !g_module_set_.Pointer()->count(library->image_path.value().c_str()); |
+ } |
+ if (unload) { |
+ if (library->type == BUNDLE) { |
+ CFBundleCloseBundleResourceMap(library->bundle, |
+ library->bundle_resource_ref); |
+ CFRelease(library->bundle); |
+ } else { |
+ dlclose(library->dylib); |
+ } |
} |
delete library; |
} |