DXR is a code search and navigation tool aimed at making sense of large projects. It supports full-text and regex searches as well as structural queries.

Mercurial (6863f516ba38)

VCS Links

Line Code
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 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#include "shared-libraries.h"

#include "ClearOnShutdown.h"
#include "mozilla/StaticMutex.h"
#include "mozilla/Unused.h"
#include "nsNativeCharsetUtils.h"
#include <AvailabilityMacros.h>

#include <dlfcn.h>
#include <mach-o/arch.h>
#include <mach-o/dyld_images.h>
#include <mach-o/dyld.h>
#include <mach-o/loader.h>
#include <mach/mach_init.h>
#include <mach/mach_traps.h>
#include <mach/task_info.h>
#include <mach/task.h>
#include <sstream>
#include <stdlib.h>
#include <string.h>
#include <vector>

// Architecture specific abstraction.
#if defined(GP_ARCH_x86)
typedef mach_header platform_mach_header;
typedef segment_command mach_segment_command_type;
#  define MACHO_MAGIC_NUMBER MH_MAGIC
#  define CMD_SEGMENT LC_SEGMENT
#  define seg_size uint32_t
#else
typedef mach_header_64 platform_mach_header;
typedef segment_command_64 mach_segment_command_type;
#  define MACHO_MAGIC_NUMBER MH_MAGIC_64
#  define CMD_SEGMENT LC_SEGMENT_64
#  define seg_size uint64_t
#endif

struct NativeSharedLibrary {
  const platform_mach_header* header;
  std::string path;
};
static std::vector<NativeSharedLibrary>* sSharedLibrariesList = nullptr;
static mozilla::StaticMutex sSharedLibrariesMutex;

static void SharedLibraryAddImage(const struct mach_header* mh,
                                  intptr_t vmaddr_slide) {
  // NOTE: Presumably for backwards-compatibility reasons, this function accepts
  // a mach_header even on 64-bit where it ought to be a mach_header_64. We cast
  // it to the right type here.
  auto header = reinterpret_cast<const platform_mach_header*>(mh);

  Dl_info info;
  if (!dladdr(header, &info)) {
    return;
  }

  mozilla::StaticMutexAutoLock lock(sSharedLibrariesMutex);
  if (!sSharedLibrariesList) {
    return;
  }

  NativeSharedLibrary lib = {header, info.dli_fname};
  sSharedLibrariesList->push_back(lib);
}

static void SharedLibraryRemoveImage(const struct mach_header* mh,
                                     intptr_t vmaddr_slide) {
  // NOTE: Presumably for backwards-compatibility reasons, this function accepts
  // a mach_header even on 64-bit where it ought to be a mach_header_64. We cast
  // it to the right type here.
  auto header = reinterpret_cast<const platform_mach_header*>(mh);

  mozilla::StaticMutexAutoLock lock(sSharedLibrariesMutex);
  if (!sSharedLibrariesList) {
    return;
  }

  uint32_t count = sSharedLibrariesList->size();
  for (uint32_t i = 0; i < count; ++i) {
    if ((*sSharedLibrariesList)[i].header == header) {
      sSharedLibrariesList->erase(sSharedLibrariesList->begin() + i);
      return;
    }
  }
}

void SharedLibraryInfo::Initialize() {
  // NOTE: We intentionally leak this memory here. We're allocating dynamically
  // in order to avoid static initializers.
  sSharedLibrariesList = new std::vector<NativeSharedLibrary>();

  _dyld_register_func_for_add_image(SharedLibraryAddImage);
  _dyld_register_func_for_remove_image(SharedLibraryRemoveImage);
}

static void addSharedLibrary(const platform_mach_header* header,
                             const char* path, SharedLibraryInfo& info) {
  const struct load_command* cmd =
      reinterpret_cast<const struct load_command*>(header + 1);

  seg_size size = 0;
  unsigned long long start = reinterpret_cast<unsigned long long>(header);
  // Find the cmd segment in the macho image. It will contain the offset we care
  // about.
  const uint8_t* uuid_bytes = nullptr;
  for (unsigned int i = 0;
       cmd && (i < header->ncmds) && (uuid_bytes == nullptr || size == 0);
       ++i) {
    if (cmd->cmd == CMD_SEGMENT) {
      const mach_segment_command_type* seg =
          reinterpret_cast<const mach_segment_command_type*>(cmd);

      if (!strcmp(seg->segname, "__TEXT")) {
        size = seg->vmsize;
      }
    } else if (cmd->cmd == LC_UUID) {
      const uuid_command* ucmd = reinterpret_cast<const uuid_command*>(cmd);
      uuid_bytes = ucmd->uuid;
    }

    cmd = reinterpret_cast<const struct load_command*>(
        reinterpret_cast<const char*>(cmd) + cmd->cmdsize);
  }

  nsAutoCString uuid;
  if (uuid_bytes != nullptr) {
    uuid.AppendPrintf(
        "%02X"
        "%02X"
        "%02X"
        "%02X"
        "%02X"
        "%02X"
        "%02X"
        "%02X"
        "%02X"
        "%02X"
        "%02X"
        "%02X"
        "%02X"
        "%02X"
        "%02X"
        "%02X"
        "0" /* breakpad id age */,
        uuid_bytes[0], uuid_bytes[1], uuid_bytes[2], uuid_bytes[3],
        uuid_bytes[4], uuid_bytes[5], uuid_bytes[6], uuid_bytes[7],
        uuid_bytes[8], uuid_bytes[9], uuid_bytes[10], uuid_bytes[11],
        uuid_bytes[12], uuid_bytes[13], uuid_bytes[14], uuid_bytes[15]);
  }

  nsAutoString pathStr;
  mozilla::Unused << NS_WARN_IF(
      NS_FAILED(NS_CopyNativeToUnicode(nsDependentCString(path), pathStr)));

  nsAutoString nameStr = pathStr;
  int32_t pos = nameStr.RFindChar('/');
  if (pos != kNotFound) {
    nameStr.Cut(0, pos + 1);
  }

  const NXArchInfo* archInfo =
      NXGetArchInfoFromCpuType(header->cputype, header->cpusubtype);

  info.AddSharedLibrary(SharedLibrary(start, start + size, 0, uuid, nameStr,
                                      pathStr, nameStr, pathStr, EmptyCString(),
                                      archInfo ? archInfo->name : ""));
}

// Translate the statically stored sSharedLibrariesList information into a
// SharedLibraryInfo object.
SharedLibraryInfo SharedLibraryInfo::GetInfoForSelf() {
  mozilla::StaticMutexAutoLock lock(sSharedLibrariesMutex);
  SharedLibraryInfo sharedLibraryInfo;

  for (auto& info : *sSharedLibrariesList) {
    addSharedLibrary(info.header, info.path.c_str(), sharedLibraryInfo);
  }

  return sharedLibraryInfo;
}