tools/profiler/AutoObjectMapper.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/tools/profiler/AutoObjectMapper.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,207 @@
     1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     1.5 +/* vim: set ts=8 sts=2 et sw=2 tw=80: */
     1.6 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.9 +
    1.10 +#include <sys/mman.h>
    1.11 +#include <unistd.h>
    1.12 +#include <sys/types.h>
    1.13 +#include <sys/stat.h>
    1.14 +#include <fcntl.h>
    1.15 +
    1.16 +#include "mozilla/Assertions.h"
    1.17 +#include "mozilla/NullPtr.h"
    1.18 +
    1.19 +#include "PlatformMacros.h"
    1.20 +#include "AutoObjectMapper.h"
    1.21 +
    1.22 +#if defined(SPS_OS_android) && !defined(MOZ_WIDGET_GONK)
    1.23 +# include <dlfcn.h>
    1.24 +# include "mozilla/Types.h"
    1.25 +  // FIXME move these out of mozglue/linker/ElfLoader.h into their
    1.26 +  // own header, so as to avoid conflicts arising from two definitions
    1.27 +  // of Array
    1.28 +  extern "C" {
    1.29 +    MFBT_API size_t
    1.30 +    __dl_get_mappable_length(void *handle);
    1.31 +    MFBT_API void *
    1.32 +    __dl_mmap(void *handle, void *addr, size_t length, off_t offset);
    1.33 +    MFBT_API void
    1.34 +    __dl_munmap(void *handle, void *addr, size_t length);
    1.35 +  }
    1.36 +  // The following are for get_installation_lib_dir()
    1.37 +# include "nsString.h"
    1.38 +# include "nsDirectoryServiceUtils.h"
    1.39 +# include "nsDirectoryServiceDefs.h"
    1.40 +#endif
    1.41 +
    1.42 +
    1.43 +// A helper function for creating failure error messages in
    1.44 +// AutoObjectMapper*::Map.
    1.45 +static void
    1.46 +failedToMessage(void(*aLog)(const char*),
    1.47 +                const char* aHowFailed, std::string aFileName)
    1.48 +{
    1.49 +  char buf[300];
    1.50 +  snprintf(buf, sizeof(buf), "AutoObjectMapper::Map: Failed to %s \'%s\'",
    1.51 +           aHowFailed, aFileName.c_str());
    1.52 +  buf[sizeof(buf)-1] = 0;
    1.53 +  aLog(buf);
    1.54 +}
    1.55 +
    1.56 +
    1.57 +AutoObjectMapperPOSIX::AutoObjectMapperPOSIX(void(*aLog)(const char*))
    1.58 +  : mImage(nullptr)
    1.59 +  , mSize(0)
    1.60 +  , mLog(aLog)
    1.61 +  , mIsMapped(false)
    1.62 +{}
    1.63 +
    1.64 +AutoObjectMapperPOSIX::~AutoObjectMapperPOSIX() {
    1.65 +  if (!mIsMapped) {
    1.66 +    // There's nothing to do.
    1.67 +    MOZ_ASSERT(!mImage);
    1.68 +    MOZ_ASSERT(mSize == 0);
    1.69 +    return;
    1.70 +  }
    1.71 +  MOZ_ASSERT(mSize > 0);
    1.72 +  // The following assertion doesn't necessarily have to be true,
    1.73 +  // but we assume (reasonably enough) that no mmap facility would
    1.74 +  // be crazy enough to map anything at page zero.
    1.75 +  MOZ_ASSERT(mImage);
    1.76 +  munmap(mImage, mSize);
    1.77 +}
    1.78 +
    1.79 +bool AutoObjectMapperPOSIX::Map(/*OUT*/void** start, /*OUT*/size_t* length,
    1.80 +                                std::string fileName)
    1.81 +{
    1.82 +  MOZ_ASSERT(!mIsMapped);
    1.83 +
    1.84 +  int fd = open(fileName.c_str(), O_RDONLY);
    1.85 +  if (fd == -1) {
    1.86 +    failedToMessage(mLog, "open", fileName);
    1.87 +    return false;
    1.88 +  }
    1.89 +
    1.90 +  struct stat st;
    1.91 +  int    err = fstat(fd, &st);
    1.92 +  size_t sz  = (err == 0) ? st.st_size : 0;
    1.93 +  if (err != 0 || sz == 0) {
    1.94 +    failedToMessage(mLog, "fstat", fileName);
    1.95 +    close(fd);
    1.96 +    return false;
    1.97 +  }
    1.98 +
    1.99 +  void* image = mmap(nullptr, sz, PROT_READ, MAP_SHARED, fd, 0);
   1.100 +  if (image == MAP_FAILED) {
   1.101 +    failedToMessage(mLog, "mmap", fileName);
   1.102 +    close(fd);
   1.103 +    return false;
   1.104 +  }
   1.105 +
   1.106 +  close(fd);
   1.107 +  mIsMapped = true;
   1.108 +  mImage = *start  = image;
   1.109 +  mSize  = *length = sz;
   1.110 +  return true;
   1.111 +}
   1.112 +
   1.113 +
   1.114 +#if defined(SPS_OS_android) && !defined(MOZ_WIDGET_GONK)
   1.115 +// A helper function for AutoObjectMapperFaultyLib::Map.  Finds out
   1.116 +// where the installation's lib directory is, since we'll have to look
   1.117 +// in there to get hold of libmozglue.so.  Returned C string is heap
   1.118 +// allocated and the caller must deallocate it.
   1.119 +static char*
   1.120 +get_installation_lib_dir()
   1.121 +{
   1.122 +  nsCOMPtr<nsIProperties>
   1.123 +    directoryService(do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID));
   1.124 +  if (!directoryService) {
   1.125 +    return nullptr;
   1.126 +  }
   1.127 +  nsCOMPtr<nsIFile> greDir;
   1.128 +  nsresult rv = directoryService->Get(NS_GRE_DIR, NS_GET_IID(nsIFile),
   1.129 +                                      getter_AddRefs(greDir));
   1.130 +  if (NS_FAILED(rv)) return nullptr;
   1.131 +  nsCString path;
   1.132 +  rv = greDir->GetNativePath(path);
   1.133 +  if (NS_FAILED(rv)) {
   1.134 +    return nullptr;
   1.135 +  }
   1.136 +  return strdup(path.get());
   1.137 +}
   1.138 +
   1.139 +AutoObjectMapperFaultyLib::AutoObjectMapperFaultyLib(void(*aLog)(const char*))
   1.140 +  : AutoObjectMapperPOSIX(aLog)
   1.141 +  , mHdl(nullptr)
   1.142 +{}
   1.143 +
   1.144 +AutoObjectMapperFaultyLib::~AutoObjectMapperFaultyLib() {
   1.145 +  if (mHdl) {
   1.146 +    // We've got an object mapped by faulty.lib.  Unmap it via faulty.lib.
   1.147 +    MOZ_ASSERT(mSize > 0);
   1.148 +    // Assert on the basis that no valid mapping would start at page zero.
   1.149 +    MOZ_ASSERT(mImage);
   1.150 +    __dl_munmap(mHdl, mImage, mSize);
   1.151 +    dlclose(mHdl);
   1.152 +    // Stop assertions in ~AutoObjectMapperPOSIX from failing.
   1.153 +    mImage = nullptr;
   1.154 +    mSize  = 0;
   1.155 +  }
   1.156 +  // At this point the parent class destructor, ~AutoObjectMapperPOSIX,
   1.157 +  // gets called.  If that has something mapped in the normal way, it
   1.158 +  // will unmap it in the normal way.  Unfortunately there's no
   1.159 +  // obvious way to enforce the requirement that the object is mapped
   1.160 +  // either by faulty.lib or by the parent class, but not by both.
   1.161 +}
   1.162 +
   1.163 +bool AutoObjectMapperFaultyLib::Map(/*OUT*/void** start, /*OUT*/size_t* length,
   1.164 +                                    std::string fileName)
   1.165 +{
   1.166 +  MOZ_ASSERT(!mHdl);
   1.167 +
   1.168 +  if (fileName == "libmozglue.so") {
   1.169 +
   1.170 +    // Do (2) in the comment above.
   1.171 +    char* libdir = get_installation_lib_dir();
   1.172 +    if (libdir) {
   1.173 +      fileName = std::string(libdir) + "/lib/" + fileName;
   1.174 +      free(libdir);
   1.175 +    }
   1.176 +    // Hand the problem off to the standard mapper.
   1.177 +    return AutoObjectMapperPOSIX::Map(start, length, fileName);
   1.178 +
   1.179 +  } else {
   1.180 +
   1.181 +    // Do cases (1) and (3) in the comment above.  We have to
   1.182 +    // grapple with faulty.lib directly.
   1.183 +    void* hdl = dlopen(fileName.c_str(), RTLD_GLOBAL | RTLD_LAZY);
   1.184 +    if (!hdl) {
   1.185 +      failedToMessage(mLog, "get handle for ELF file", fileName);
   1.186 +      return false;
   1.187 +    }
   1.188 +
   1.189 +    size_t sz = __dl_get_mappable_length(hdl);
   1.190 +    if (sz == 0) {
   1.191 +      dlclose(hdl);
   1.192 +      failedToMessage(mLog, "get size for ELF file", fileName);
   1.193 +      return false;
   1.194 +    }
   1.195 +
   1.196 +    void* image = __dl_mmap(hdl, nullptr, sz, 0);
   1.197 +    if (image == MAP_FAILED) {
   1.198 +      dlclose(hdl);
   1.199 +      failedToMessage(mLog, "mmap ELF file", fileName);
   1.200 +      return false;
   1.201 +    }
   1.202 +
   1.203 +    mHdl   = hdl;
   1.204 +    mImage = *start  = image;
   1.205 +    mSize  = *length = sz;
   1.206 +    return true;
   1.207 +  }
   1.208 +}
   1.209 +
   1.210 +#endif // defined(SPS_OS_android) && !defined(MOZ_WIDGET_GONK)

mercurial