• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Copyright 2011 The Chromium Authors
2// 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
7#include <dlfcn.h>
8#include <mach-o/getsect.h>
9
10#include "base/apple/scoped_cftyperef.h"
11#include "base/files/file_path.h"
12#include "base/files/file_util.h"
13#include "base/logging.h"
14#include "base/strings/strcat.h"
15#include "base/strings/string_piece.h"
16#include "base/strings/string_util.h"
17#include "base/strings/utf_string_conversions.h"
18#include "base/threading/thread_restrictions.h"
19
20namespace base {
21
22static NativeLibraryObjCStatus GetObjCStatusForImage(
23    const void* function_pointer) {
24  Dl_info info;
25  if (!dladdr(function_pointer, &info))
26    return OBJC_UNKNOWN;
27
28  // See if the image contains an "ObjC image info" segment. This method
29  // of testing is used in _CFBundleGrokObjcImageInfoFromFile in
30  // CF-1153.18/CFBundle_Grok.c, around line 349.
31  //
32  // In 64-bit images, ObjC can be recognized in __DATA,__objc_imageinfo.
33  const auto* header =
34      reinterpret_cast<const struct mach_header_64*>(info.dli_fbase);
35  unsigned long size = 0;
36  getsectiondata(header, SEG_DATA, "__objc_imageinfo", &size);
37  if (size > 0) {
38    return OBJC_PRESENT;
39  }
40  // ....except when "SharedRegionEncodingV2" is on, it's in
41  // __DATA_CONST,__objc_image_info (see https://crbug.com/1220459#c16)
42  getsectiondata(header, "__DATA_CONST", "__objc_imageinfo", &size);
43  return size > 0 ? OBJC_PRESENT : OBJC_NOT_PRESENT;
44}
45
46std::string NativeLibraryLoadError::ToString() const {
47  return message;
48}
49
50NativeLibrary LoadNativeLibraryWithOptions(const FilePath& library_path,
51                                           const NativeLibraryOptions& options,
52                                           NativeLibraryLoadError* error) {
53  // dlopen() etc. open the file off disk.
54  if (library_path.Extension() == "dylib" || !DirectoryExists(library_path)) {
55    void* dylib = dlopen(library_path.value().c_str(), RTLD_LAZY);
56    if (!dylib) {
57      if (error)
58        error->message = dlerror();
59      return nullptr;
60    }
61    NativeLibrary native_lib = new NativeLibraryStruct();
62    native_lib->type = DYNAMIC_LIB;
63    native_lib->dylib = dylib;
64    native_lib->objc_status = OBJC_UNKNOWN;
65    return native_lib;
66  }
67  apple::ScopedCFTypeRef<CFURLRef> url(CFURLCreateFromFileSystemRepresentation(
68      kCFAllocatorDefault, (const UInt8*)library_path.value().c_str(),
69      checked_cast<CFIndex>(library_path.value().length()), true));
70  if (!url)
71    return nullptr;
72  CFBundleRef bundle = CFBundleCreate(kCFAllocatorDefault, url.get());
73  if (!bundle)
74    return nullptr;
75
76  NativeLibrary native_lib = new NativeLibraryStruct();
77  native_lib->type = BUNDLE;
78  native_lib->bundle = bundle;
79  native_lib->objc_status = OBJC_UNKNOWN;
80  return native_lib;
81}
82
83void UnloadNativeLibrary(NativeLibrary library) {
84  if (library->objc_status == OBJC_NOT_PRESENT) {
85    if (library->type == BUNDLE) {
86      CFRelease(library->bundle);
87    } else {
88      dlclose(library->dylib);
89    }
90  } else {
91    VLOG(2) << "Not unloading NativeLibrary because it may contain an ObjC "
92               "segment. library->objc_status = " << library->objc_status;
93    // Deliberately do not CFRelease the bundle or dlclose the dylib because
94    // doing so can corrupt the ObjC runtime method caches. See
95    // http://crbug.com/172319 for details.
96  }
97  delete library;
98}
99
100void* GetFunctionPointerFromNativeLibrary(NativeLibrary library,
101                                          const char* name) {
102  void* function_pointer = nullptr;
103
104  // Get the function pointer using the right API for the type.
105  if (library->type == BUNDLE) {
106    apple::ScopedCFTypeRef<CFStringRef> symbol_name(CFStringCreateWithCString(
107        kCFAllocatorDefault, name, kCFStringEncodingUTF8));
108    function_pointer =
109        CFBundleGetFunctionPointerForName(library->bundle, symbol_name.get());
110  } else {
111    function_pointer = dlsym(library->dylib, name);
112  }
113
114  // If this library hasn't been tested for having ObjC, use the function
115  // pointer to look up the section information for the library.
116  if (function_pointer && library->objc_status == OBJC_UNKNOWN)
117    library->objc_status = GetObjCStatusForImage(function_pointer);
118
119  return function_pointer;
120}
121
122std::string GetNativeLibraryName(StringPiece name) {
123  DCHECK(IsStringASCII(name));
124  return StrCat({"lib", name, ".dylib"});
125}
126
127std::string GetLoadableModuleName(StringPiece name) {
128  DCHECK(IsStringASCII(name));
129  return StrCat({name, ".so"});
130}
131
132}  // namespace base
133