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
133
134
135
136
137
|
// 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/files/file_path.h"
#include "base/files/file_util.h"
#include "base/logging.h"
#include "base/mac/scoped_cftyperef.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-744/CFBundle.c, around lines 2447-2474.
//
// In 64-bit images, ObjC can be recognized in __DATA,__objc_imageinfo.
const section_64* section = getsectbynamefromheader_64(
reinterpret_cast<const struct mach_header_64*>(info.dli_fbase), SEG_DATA,
"__objc_imageinfo");
if (section)
return OBJC_PRESENT;
// ....except when "SharedRegionEncodingV2" is on, it's in
// __DATA_CONST,__objc_image_info (see https://crbug.com/1220459#c16)
section = getsectbynamefromheader_64(
reinterpret_cast<const struct mach_header_64*>(info.dli_fbase),
"__DATA_CONST", "__objc_imageinfo");
return section ? 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;
}
ScopedCFTypeRef<CFURLRef> url(CFURLCreateFromFileSystemRepresentation(
kCFAllocatorDefault,
(const UInt8*)library_path.value().c_str(),
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->bundle_resource_ref = CFBundleOpenBundleResourceMap(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) {
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;
}
void* GetFunctionPointerFromNativeLibrary(NativeLibrary library,
StringPiece name) {
void* function_pointer = nullptr;
// Get the function pointer using the right API for the type.
if (library->type == BUNDLE) {
ScopedCFTypeRef<CFStringRef> symbol_name(CFStringCreateWithCString(
kCFAllocatorDefault, name.data(), kCFStringEncodingUTF8));
function_pointer = CFBundleGetFunctionPointerForName(library->bundle,
symbol_name);
} else {
function_pointer = dlsym(library->dylib, name.data());
}
// 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
|