mozglue/linker/ElfLoader.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/mozglue/linker/ElfLoader.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,1126 @@
     1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this file,
     1.6 + * You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.7 +
     1.8 +#include <string>
     1.9 +#include <cstring>
    1.10 +#include <cstdlib>
    1.11 +#include <cstdio>
    1.12 +#include <dlfcn.h>
    1.13 +#include <unistd.h>
    1.14 +#include <algorithm>
    1.15 +#include <fcntl.h>
    1.16 +#include "ElfLoader.h"
    1.17 +#include "CustomElf.h"
    1.18 +#include "Mappable.h"
    1.19 +#include "Logging.h"
    1.20 +#include <inttypes.h>
    1.21 +
    1.22 +#if defined(ANDROID)
    1.23 +#include <sys/syscall.h>
    1.24 +
    1.25 +#include <android/api-level.h>
    1.26 +#if __ANDROID_API__ < 8
    1.27 +/* Android API < 8 doesn't provide sigaltstack */
    1.28 +
    1.29 +extern "C" {
    1.30 +
    1.31 +inline int sigaltstack(const stack_t *ss, stack_t *oss) {
    1.32 +  return syscall(__NR_sigaltstack, ss, oss);
    1.33 +}
    1.34 +
    1.35 +} /* extern "C" */
    1.36 +#endif /* __ANDROID_API__ */
    1.37 +#endif /* ANDROID */
    1.38 +
    1.39 +#ifdef __ARM_EABI__
    1.40 +extern "C" const void *
    1.41 +__gnu_Unwind_Find_exidx(void *pc, int *pcount) __attribute__((weak));
    1.42 +#endif
    1.43 +
    1.44 +using namespace mozilla;
    1.45 +
    1.46 +/**
    1.47 + * dlfcn.h replacements functions
    1.48 + */
    1.49 +
    1.50 +void *
    1.51 +__wrap_dlopen(const char *path, int flags)
    1.52 +{
    1.53 +  RefPtr<LibHandle> handle = ElfLoader::Singleton.Load(path, flags);
    1.54 +  if (handle)
    1.55 +    handle->AddDirectRef();
    1.56 +  return handle;
    1.57 +}
    1.58 +
    1.59 +const char *
    1.60 +__wrap_dlerror(void)
    1.61 +{
    1.62 +  const char *error = ElfLoader::Singleton.lastError;
    1.63 +  ElfLoader::Singleton.lastError = nullptr;
    1.64 +  return error;
    1.65 +}
    1.66 +
    1.67 +void *
    1.68 +__wrap_dlsym(void *handle, const char *symbol)
    1.69 +{
    1.70 +  if (!handle) {
    1.71 +    ElfLoader::Singleton.lastError = "dlsym(NULL, sym) unsupported";
    1.72 +    return nullptr;
    1.73 +  }
    1.74 +  if (handle != RTLD_DEFAULT && handle != RTLD_NEXT) {
    1.75 +    LibHandle *h = reinterpret_cast<LibHandle *>(handle);
    1.76 +    return h->GetSymbolPtr(symbol);
    1.77 +  }
    1.78 +  return dlsym(handle, symbol);
    1.79 +}
    1.80 +
    1.81 +int
    1.82 +__wrap_dlclose(void *handle)
    1.83 +{
    1.84 +  if (!handle) {
    1.85 +    ElfLoader::Singleton.lastError = "No handle given to dlclose()";
    1.86 +    return -1;
    1.87 +  }
    1.88 +  reinterpret_cast<LibHandle *>(handle)->ReleaseDirectRef();
    1.89 +  return 0;
    1.90 +}
    1.91 +
    1.92 +int
    1.93 +__wrap_dladdr(void *addr, Dl_info *info)
    1.94 +{
    1.95 +  RefPtr<LibHandle> handle = ElfLoader::Singleton.GetHandleByPtr(addr);
    1.96 +  if (!handle)
    1.97 +    return 0;
    1.98 +  info->dli_fname = handle->GetPath();
    1.99 +  return 1;
   1.100 +}
   1.101 +
   1.102 +int
   1.103 +__wrap_dl_iterate_phdr(dl_phdr_cb callback, void *data)
   1.104 +{
   1.105 +  if (!ElfLoader::Singleton.dbg)
   1.106 +    return -1;
   1.107 +
   1.108 +  for (ElfLoader::DebuggerHelper::iterator it = ElfLoader::Singleton.dbg.begin();
   1.109 +       it < ElfLoader::Singleton.dbg.end(); ++it) {
   1.110 +    dl_phdr_info info;
   1.111 +    info.dlpi_addr = reinterpret_cast<Elf::Addr>(it->l_addr);
   1.112 +    info.dlpi_name = it->l_name;
   1.113 +    info.dlpi_phdr = nullptr;
   1.114 +    info.dlpi_phnum = 0;
   1.115 +
   1.116 +    // Assuming l_addr points to Elf headers (in most cases, this is true),
   1.117 +    // get the Phdr location from there.
   1.118 +    uint8_t mapped;
   1.119 +    // If the page is not mapped, mincore returns an error.
   1.120 +    if (!mincore(const_cast<void*>(it->l_addr), PageSize(), &mapped)) {
   1.121 +      const Elf::Ehdr *ehdr = Elf::Ehdr::validate(it->l_addr);
   1.122 +      if (ehdr) {
   1.123 +        info.dlpi_phdr = reinterpret_cast<const Elf::Phdr *>(
   1.124 +                         reinterpret_cast<const char *>(ehdr) + ehdr->e_phoff);
   1.125 +        info.dlpi_phnum = ehdr->e_phnum;
   1.126 +      }
   1.127 +    }
   1.128 +
   1.129 +    int ret = callback(&info, sizeof(dl_phdr_info), data);
   1.130 +    if (ret)
   1.131 +      return ret;
   1.132 +  }
   1.133 +  return 0;
   1.134 +}
   1.135 +
   1.136 +#ifdef __ARM_EABI__
   1.137 +const void *
   1.138 +__wrap___gnu_Unwind_Find_exidx(void *pc, int *pcount)
   1.139 +{
   1.140 +  RefPtr<LibHandle> handle = ElfLoader::Singleton.GetHandleByPtr(pc);
   1.141 +  if (handle)
   1.142 +    return handle->FindExidx(pcount);
   1.143 +  if (__gnu_Unwind_Find_exidx)
   1.144 +    return __gnu_Unwind_Find_exidx(pc, pcount);
   1.145 +  *pcount = 0;
   1.146 +  return nullptr;
   1.147 +}
   1.148 +#endif
   1.149 +
   1.150 +/**
   1.151 + * faulty.lib public API
   1.152 + */
   1.153 +
   1.154 +MFBT_API size_t
   1.155 +__dl_get_mappable_length(void *handle) {
   1.156 +  if (!handle)
   1.157 +    return 0;
   1.158 +  return reinterpret_cast<LibHandle *>(handle)->GetMappableLength();
   1.159 +}
   1.160 +
   1.161 +MFBT_API void *
   1.162 +__dl_mmap(void *handle, void *addr, size_t length, off_t offset)
   1.163 +{
   1.164 +  if (!handle)
   1.165 +    return nullptr;
   1.166 +  return reinterpret_cast<LibHandle *>(handle)->MappableMMap(addr, length,
   1.167 +                                                             offset);
   1.168 +}
   1.169 +
   1.170 +MFBT_API void
   1.171 +__dl_munmap(void *handle, void *addr, size_t length)
   1.172 +{
   1.173 +  if (!handle)
   1.174 +    return;
   1.175 +  return reinterpret_cast<LibHandle *>(handle)->MappableMUnmap(addr, length);
   1.176 +}
   1.177 +
   1.178 +MFBT_API bool
   1.179 +IsSignalHandlingBroken()
   1.180 +{
   1.181 +  return ElfLoader::Singleton.isSignalHandlingBroken();
   1.182 +}
   1.183 +
   1.184 +namespace {
   1.185 +
   1.186 +/**
   1.187 + * Returns the part after the last '/' for the given path
   1.188 + */
   1.189 +const char *
   1.190 +LeafName(const char *path)
   1.191 +{
   1.192 +  const char *lastSlash = strrchr(path, '/');
   1.193 +  if (lastSlash)
   1.194 +    return lastSlash + 1;
   1.195 +  return path;
   1.196 +}
   1.197 +
   1.198 +} /* Anonymous namespace */
   1.199 +
   1.200 +/**
   1.201 + * LibHandle
   1.202 + */
   1.203 +LibHandle::~LibHandle()
   1.204 +{
   1.205 +  free(path);
   1.206 +}
   1.207 +
   1.208 +const char *
   1.209 +LibHandle::GetName() const
   1.210 +{
   1.211 +  return path ? LeafName(path) : nullptr;
   1.212 +}
   1.213 +
   1.214 +size_t
   1.215 +LibHandle::GetMappableLength() const
   1.216 +{
   1.217 +  if (!mappable)
   1.218 +    mappable = GetMappable();
   1.219 +  if (!mappable)
   1.220 +    return 0;
   1.221 +  return mappable->GetLength();
   1.222 +}
   1.223 +
   1.224 +void *
   1.225 +LibHandle::MappableMMap(void *addr, size_t length, off_t offset) const
   1.226 +{
   1.227 +  if (!mappable)
   1.228 +    mappable = GetMappable();
   1.229 +  if (!mappable)
   1.230 +    return MAP_FAILED;
   1.231 +  void* mapped = mappable->mmap(addr, length, PROT_READ, MAP_PRIVATE, offset);
   1.232 +  if (mapped != MAP_FAILED) {
   1.233 +    /* Ensure the availability of all pages within the mapping */
   1.234 +    for (size_t off = 0; off < length; off += PageSize()) {
   1.235 +      mappable->ensure(reinterpret_cast<char *>(mapped) + off);
   1.236 +    }
   1.237 +  }
   1.238 +  return mapped;
   1.239 +}
   1.240 +
   1.241 +void
   1.242 +LibHandle::MappableMUnmap(void *addr, size_t length) const
   1.243 +{
   1.244 +  if (mappable)
   1.245 +    mappable->munmap(addr, length);
   1.246 +}
   1.247 +
   1.248 +/**
   1.249 + * SystemElf
   1.250 + */
   1.251 +TemporaryRef<LibHandle>
   1.252 +SystemElf::Load(const char *path, int flags)
   1.253 +{
   1.254 +  /* The Android linker returns a handle when the file name matches an
   1.255 +   * already loaded library, even when the full path doesn't exist */
   1.256 +  if (path && path[0] == '/' && (access(path, F_OK) == -1)){
   1.257 +    DEBUG_LOG("dlopen(\"%s\", 0x%x) = %p", path, flags, (void *)nullptr);
   1.258 +    return nullptr;
   1.259 +  }
   1.260 +
   1.261 +  void *handle = dlopen(path, flags);
   1.262 +  DEBUG_LOG("dlopen(\"%s\", 0x%x) = %p", path, flags, handle);
   1.263 +  ElfLoader::Singleton.lastError = dlerror();
   1.264 +  if (handle) {
   1.265 +    SystemElf *elf = new SystemElf(path, handle);
   1.266 +    ElfLoader::Singleton.Register(elf);
   1.267 +    return elf;
   1.268 +  }
   1.269 +  return nullptr;
   1.270 +}
   1.271 +
   1.272 +SystemElf::~SystemElf()
   1.273 +{
   1.274 +  if (!dlhandle)
   1.275 +    return;
   1.276 +  DEBUG_LOG("dlclose(%p [\"%s\"])", dlhandle, GetPath());
   1.277 +  dlclose(dlhandle);
   1.278 +  ElfLoader::Singleton.lastError = dlerror();
   1.279 +  ElfLoader::Singleton.Forget(this);
   1.280 +}
   1.281 +
   1.282 +void *
   1.283 +SystemElf::GetSymbolPtr(const char *symbol) const
   1.284 +{
   1.285 +  void *sym = dlsym(dlhandle, symbol);
   1.286 +  DEBUG_LOG("dlsym(%p [\"%s\"], \"%s\") = %p", dlhandle, GetPath(), symbol, sym);
   1.287 +  ElfLoader::Singleton.lastError = dlerror();
   1.288 +  return sym;
   1.289 +}
   1.290 +
   1.291 +Mappable *
   1.292 +SystemElf::GetMappable() const
   1.293 +{
   1.294 +  const char *path = GetPath();
   1.295 +  if (!path)
   1.296 +    return nullptr;
   1.297 +#ifdef ANDROID
   1.298 +  /* On Android, if we don't have the full path, try in /system/lib */
   1.299 +  const char *name = LeafName(path);
   1.300 +  std::string systemPath;
   1.301 +  if (name == path) {
   1.302 +    systemPath = "/system/lib/";
   1.303 +    systemPath += path;
   1.304 +    path = systemPath.c_str();
   1.305 +  }
   1.306 +#endif
   1.307 +
   1.308 +  return MappableFile::Create(path);
   1.309 +}
   1.310 +
   1.311 +#ifdef __ARM_EABI__
   1.312 +const void *
   1.313 +SystemElf::FindExidx(int *pcount) const
   1.314 +{
   1.315 +  /* TODO: properly implement when ElfLoader::GetHandleByPtr
   1.316 +     does return SystemElf handles */
   1.317 +  *pcount = 0;
   1.318 +  return nullptr;
   1.319 +}
   1.320 +#endif
   1.321 +
   1.322 +/**
   1.323 + * ElfLoader
   1.324 + */
   1.325 +
   1.326 +/* Unique ElfLoader instance */
   1.327 +ElfLoader ElfLoader::Singleton;
   1.328 +
   1.329 +TemporaryRef<LibHandle>
   1.330 +ElfLoader::Load(const char *path, int flags, LibHandle *parent)
   1.331 +{
   1.332 +  /* Ensure logging is initialized or refresh if environment changed. */
   1.333 +  Logging::Init();
   1.334 +
   1.335 +  RefPtr<LibHandle> handle;
   1.336 +
   1.337 +  /* Handle dlopen(nullptr) directly. */
   1.338 +  if (!path) {
   1.339 +    handle = SystemElf::Load(nullptr, flags);
   1.340 +    return handle;
   1.341 +  }
   1.342 +
   1.343 +  /* TODO: Handle relative paths correctly */
   1.344 +  const char *name = LeafName(path);
   1.345 +
   1.346 +  /* Search the list of handles we already have for a match. When the given
   1.347 +   * path is not absolute, compare file names, otherwise compare full paths. */
   1.348 +  if (name == path) {
   1.349 +    for (LibHandleList::iterator it = handles.begin(); it < handles.end(); ++it)
   1.350 +      if ((*it)->GetName() && (strcmp((*it)->GetName(), name) == 0))
   1.351 +        return *it;
   1.352 +  } else {
   1.353 +    for (LibHandleList::iterator it = handles.begin(); it < handles.end(); ++it)
   1.354 +      if ((*it)->GetPath() && (strcmp((*it)->GetPath(), path) == 0))
   1.355 +        return *it;
   1.356 +  }
   1.357 +
   1.358 +  char *abs_path = nullptr;
   1.359 +  const char *requested_path = path;
   1.360 +
   1.361 +  /* When the path is not absolute and the library is being loaded for
   1.362 +   * another, first try to load the library from the directory containing
   1.363 +   * that parent library. */
   1.364 +  if ((name == path) && parent) {
   1.365 +    const char *parentPath = parent->GetPath();
   1.366 +    abs_path = new char[strlen(parentPath) + strlen(path)];
   1.367 +    strcpy(abs_path, parentPath);
   1.368 +    char *slash = strrchr(abs_path, '/');
   1.369 +    strcpy(slash + 1, path);
   1.370 +    path = abs_path;
   1.371 +  }
   1.372 +
   1.373 +  Mappable *mappable = GetMappableFromPath(path);
   1.374 +
   1.375 +  /* Try loading with the custom linker if we have a Mappable */
   1.376 +  if (mappable)
   1.377 +    handle = CustomElf::Load(mappable, path, flags);
   1.378 +
   1.379 +  /* Try loading with the system linker if everything above failed */
   1.380 +  if (!handle)
   1.381 +    handle = SystemElf::Load(path, flags);
   1.382 +
   1.383 +  /* If we didn't have an absolute path and haven't been able to load
   1.384 +   * a library yet, try in the system search path */
   1.385 +  if (!handle && abs_path)
   1.386 +    handle = SystemElf::Load(name, flags);
   1.387 +
   1.388 +  delete [] abs_path;
   1.389 +  DEBUG_LOG("ElfLoader::Load(\"%s\", 0x%x, %p [\"%s\"]) = %p", requested_path, flags,
   1.390 +            reinterpret_cast<void *>(parent), parent ? parent->GetPath() : "",
   1.391 +            static_cast<void *>(handle));
   1.392 +
   1.393 +  return handle;
   1.394 +}
   1.395 +
   1.396 +mozilla::TemporaryRef<LibHandle>
   1.397 +ElfLoader::GetHandleByPtr(void *addr)
   1.398 +{
   1.399 +  /* Scan the list of handles we already have for a match */
   1.400 +  for (LibHandleList::iterator it = handles.begin(); it < handles.end(); ++it) {
   1.401 +    if ((*it)->Contains(addr))
   1.402 +      return *it;
   1.403 +  }
   1.404 +  return nullptr;
   1.405 +}
   1.406 +
   1.407 +Mappable *
   1.408 +ElfLoader::GetMappableFromPath(const char *path)
   1.409 +{
   1.410 +  const char *name = LeafName(path);
   1.411 +  Mappable *mappable = nullptr;
   1.412 +  RefPtr<Zip> zip;
   1.413 +  const char *subpath;
   1.414 +  if ((subpath = strchr(path, '!'))) {
   1.415 +    char *zip_path = strndup(path, subpath - path);
   1.416 +    while (*(++subpath) == '/') { }
   1.417 +    zip = ZipCollection::GetZip(zip_path);
   1.418 +    Zip::Stream s;
   1.419 +    if (zip && zip->GetStream(subpath, &s)) {
   1.420 +      /* When the MOZ_LINKER_EXTRACT environment variable is set to "1",
   1.421 +       * compressed libraries are going to be (temporarily) extracted as
   1.422 +       * files, in the directory pointed by the MOZ_LINKER_CACHE
   1.423 +       * environment variable. */
   1.424 +      const char *extract = getenv("MOZ_LINKER_EXTRACT");
   1.425 +      if (extract && !strncmp(extract, "1", 2 /* Including '\0' */))
   1.426 +        mappable = MappableExtractFile::Create(name, zip, &s);
   1.427 +      if (!mappable) {
   1.428 +        if (s.GetType() == Zip::Stream::DEFLATE) {
   1.429 +          mappable = MappableDeflate::Create(name, zip, &s);
   1.430 +        } else if (s.GetType() == Zip::Stream::STORE) {
   1.431 +          mappable = MappableSeekableZStream::Create(name, zip, &s);
   1.432 +        }
   1.433 +      }
   1.434 +    }
   1.435 +  }
   1.436 +  /* If we couldn't load above, try with a MappableFile */
   1.437 +  if (!mappable && !zip)
   1.438 +    mappable = MappableFile::Create(path);
   1.439 +
   1.440 +  return mappable;
   1.441 +}
   1.442 +
   1.443 +void
   1.444 +ElfLoader::Register(LibHandle *handle)
   1.445 +{
   1.446 +  handles.push_back(handle);
   1.447 +  if (dbg && !handle->IsSystemElf())
   1.448 +    dbg.Add(static_cast<CustomElf *>(handle));
   1.449 +}
   1.450 +
   1.451 +void
   1.452 +ElfLoader::Forget(LibHandle *handle)
   1.453 +{
   1.454 +  /* Ensure logging is initialized or refresh if environment changed. */
   1.455 +  Logging::Init();
   1.456 +
   1.457 +  LibHandleList::iterator it = std::find(handles.begin(), handles.end(), handle);
   1.458 +  if (it != handles.end()) {
   1.459 +    DEBUG_LOG("ElfLoader::Forget(%p [\"%s\"])", reinterpret_cast<void *>(handle),
   1.460 +                                                handle->GetPath());
   1.461 +    if (dbg && !handle->IsSystemElf())
   1.462 +      dbg.Remove(static_cast<CustomElf *>(handle));
   1.463 +    handles.erase(it);
   1.464 +  } else {
   1.465 +    DEBUG_LOG("ElfLoader::Forget(%p [\"%s\"]): Handle not found",
   1.466 +              reinterpret_cast<void *>(handle), handle->GetPath());
   1.467 +  }
   1.468 +}
   1.469 +
   1.470 +ElfLoader::~ElfLoader()
   1.471 +{
   1.472 +  LibHandleList list;
   1.473 +  /* Build up a list of all library handles with direct (external) references.
   1.474 +   * We actually skip system library handles because we want to keep at least
   1.475 +   * some of these open. Most notably, Mozilla codebase keeps a few libgnome
   1.476 +   * libraries deliberately open because of the mess that libORBit destruction
   1.477 +   * is. dlclose()ing these libraries actually leads to problems. */
   1.478 +  for (LibHandleList::reverse_iterator it = handles.rbegin();
   1.479 +       it < handles.rend(); ++it) {
   1.480 +    if ((*it)->DirectRefCount()) {
   1.481 +      if ((*it)->IsSystemElf()) {
   1.482 +        static_cast<SystemElf *>(*it)->Forget();
   1.483 +      } else {
   1.484 +        list.push_back(*it);
   1.485 +      }
   1.486 +    }
   1.487 +  }
   1.488 +  /* Force release all external references to the handles collected above */
   1.489 +  for (LibHandleList::iterator it = list.begin(); it < list.end(); ++it) {
   1.490 +    while ((*it)->ReleaseDirectRef()) { }
   1.491 +  }
   1.492 +  /* Remove the remaining system handles. */
   1.493 +  if (handles.size()) {
   1.494 +    list = handles;
   1.495 +    for (LibHandleList::reverse_iterator it = list.rbegin();
   1.496 +         it < list.rend(); ++it) {
   1.497 +      if ((*it)->IsSystemElf()) {
   1.498 +        DEBUG_LOG("ElfLoader::~ElfLoader(): Remaining handle for \"%s\" "
   1.499 +                  "[%d direct refs, %d refs total]", (*it)->GetPath(),
   1.500 +                  (*it)->DirectRefCount(), (*it)->refCount());
   1.501 +      } else {
   1.502 +        DEBUG_LOG("ElfLoader::~ElfLoader(): Unexpected remaining handle for \"%s\" "
   1.503 +                  "[%d direct refs, %d refs total]", (*it)->GetPath(),
   1.504 +                  (*it)->DirectRefCount(), (*it)->refCount());
   1.505 +        /* Not removing, since it could have references to other libraries,
   1.506 +         * destroying them as a side effect, and possibly leaving dangling
   1.507 +         * pointers in the handle list we're scanning */
   1.508 +      }
   1.509 +    }
   1.510 +  }
   1.511 +}
   1.512 +
   1.513 +void
   1.514 +ElfLoader::stats(const char *when)
   1.515 +{
   1.516 +  for (LibHandleList::iterator it = Singleton.handles.begin();
   1.517 +       it < Singleton.handles.end(); ++it)
   1.518 +    if (!(*it)->IsSystemElf())
   1.519 +      static_cast<CustomElf *>(*it)->stats(when);
   1.520 +}
   1.521 +
   1.522 +#ifdef __ARM_EABI__
   1.523 +int
   1.524 +ElfLoader::__wrap_aeabi_atexit(void *that, ElfLoader::Destructor destructor,
   1.525 +                               void *dso_handle)
   1.526 +{
   1.527 +  Singleton.destructors.push_back(
   1.528 +    DestructorCaller(destructor, that, dso_handle));
   1.529 +  return 0;
   1.530 +}
   1.531 +#else
   1.532 +int
   1.533 +ElfLoader::__wrap_cxa_atexit(ElfLoader::Destructor destructor, void *that,
   1.534 +                             void *dso_handle)
   1.535 +{
   1.536 +  Singleton.destructors.push_back(
   1.537 +    DestructorCaller(destructor, that, dso_handle));
   1.538 +  return 0;
   1.539 +}
   1.540 +#endif
   1.541 +
   1.542 +void
   1.543 +ElfLoader::__wrap_cxa_finalize(void *dso_handle)
   1.544 +{
   1.545 +  /* Call all destructors for the given DSO handle in reverse order they were
   1.546 +   * registered. */
   1.547 +  std::vector<DestructorCaller>::reverse_iterator it;
   1.548 +  for (it = Singleton.destructors.rbegin();
   1.549 +       it < Singleton.destructors.rend(); ++it) {
   1.550 +    if (it->IsForHandle(dso_handle)) {
   1.551 +      it->Call();
   1.552 +    }
   1.553 +  }
   1.554 +}
   1.555 +
   1.556 +void
   1.557 +ElfLoader::DestructorCaller::Call()
   1.558 +{
   1.559 +  if (destructor) {
   1.560 +    DEBUG_LOG("ElfLoader::DestructorCaller::Call(%p, %p, %p)",
   1.561 +              FunctionPtr(destructor), object, dso_handle);
   1.562 +    destructor(object);
   1.563 +    destructor = nullptr;
   1.564 +  }
   1.565 +}
   1.566 +
   1.567 +ElfLoader::DebuggerHelper::DebuggerHelper(): dbg(nullptr)
   1.568 +{
   1.569 +  /* Find ELF auxiliary vectors.
   1.570 +   *
   1.571 +   * The kernel stores the following data on the stack when starting a
   1.572 +   * program:
   1.573 +   *   argc
   1.574 +   *   argv[0] (pointer into argv strings defined below)
   1.575 +   *   argv[1] (likewise)
   1.576 +   *   ...
   1.577 +   *   argv[argc - 1] (likewise)
   1.578 +   *   nullptr
   1.579 +   *   envp[0] (pointer into environment strings defined below)
   1.580 +   *   envp[1] (likewise)
   1.581 +   *   ...
   1.582 +   *   envp[n] (likewise)
   1.583 +   *   nullptr
   1.584 +   *   ... (more NULLs on some platforms such as Android 4.3)
   1.585 +   *   auxv[0] (first ELF auxiliary vector)
   1.586 +   *   auxv[1] (second ELF auxiliary vector)
   1.587 +   *   ...
   1.588 +   *   auxv[p] (last ELF auxiliary vector)
   1.589 +   *   (AT_NULL, nullptr)
   1.590 +   *   padding
   1.591 +   *   argv strings, separated with '\0'
   1.592 +   *   environment strings, separated with '\0'
   1.593 +   *   nullptr
   1.594 +   *
   1.595 +   * What we are after are the auxv values defined by the following struct.
   1.596 +   */
   1.597 +  struct AuxVector {
   1.598 +    Elf::Addr type;
   1.599 +    Elf::Addr value;
   1.600 +  };
   1.601 +
   1.602 +  /* Pointer to the environment variables list */
   1.603 +  extern char **environ;
   1.604 +
   1.605 +  /* The environment may have changed since the program started, in which
   1.606 +   * case the environ variables list isn't the list the kernel put on stack
   1.607 +   * anymore. But in this new list, variables that didn't change still point
   1.608 +   * to the strings the kernel put on stack. It is quite unlikely that two
   1.609 +   * modified environment variables point to two consecutive strings in memory,
   1.610 +   * so we assume that if two consecutive environment variables point to two
   1.611 +   * consecutive strings, we found strings the kernel put on stack. */
   1.612 +  char **env;
   1.613 +  for (env = environ; *env; env++)
   1.614 +    if (*env + strlen(*env) + 1 == env[1])
   1.615 +      break;
   1.616 +  if (!*env)
   1.617 +    return;
   1.618 +
   1.619 +  /* Next, we scan the stack backwards to find a pointer to one of those
   1.620 +   * strings we found above, which will give us the location of the original
   1.621 +   * envp list. As we are looking for pointers, we need to look at 32-bits or
   1.622 +   * 64-bits aligned values, depening on the architecture. */
   1.623 +  char **scan = reinterpret_cast<char **>(
   1.624 +                reinterpret_cast<uintptr_t>(*env) & ~(sizeof(void *) - 1));
   1.625 +  while (*env != *scan)
   1.626 +    scan--;
   1.627 +
   1.628 +  /* Finally, scan forward to find the last environment variable pointer and
   1.629 +   * thus the first auxiliary vector. */
   1.630 +  while (*scan++);
   1.631 +
   1.632 +  /* Some platforms have more NULLs here, so skip them if we encounter them */
   1.633 +  while (!*scan)
   1.634 +    scan++;
   1.635 +
   1.636 +  AuxVector *auxv = reinterpret_cast<AuxVector *>(scan);
   1.637 +
   1.638 +  /* The two values of interest in the auxiliary vectors are AT_PHDR and
   1.639 +   * AT_PHNUM, which gives us the the location and size of the ELF program
   1.640 +   * headers. */
   1.641 +  Array<Elf::Phdr> phdrs;
   1.642 +  char *base = nullptr;
   1.643 +  while (auxv->type) {
   1.644 +    if (auxv->type == AT_PHDR) {
   1.645 +      phdrs.Init(reinterpret_cast<Elf::Phdr*>(auxv->value));
   1.646 +      /* Assume the base address is the first byte of the same page */
   1.647 +      base = reinterpret_cast<char *>(PageAlignedPtr(auxv->value));
   1.648 +    }
   1.649 +    if (auxv->type == AT_PHNUM)
   1.650 +      phdrs.Init(auxv->value);
   1.651 +    auxv++;
   1.652 +  }
   1.653 +
   1.654 +  if (!phdrs) {
   1.655 +    DEBUG_LOG("Couldn't find program headers");
   1.656 +    return;
   1.657 +  }
   1.658 +
   1.659 +  /* In some cases, the address for the program headers we get from the
   1.660 +   * auxiliary vectors is not mapped, because of the PT_LOAD segments
   1.661 +   * definitions in the program executable. Trying to map anonymous memory
   1.662 +   * with a hint giving the base address will return a different address
   1.663 +   * if something is mapped there, and the base address otherwise. */
   1.664 +  MappedPtr mem(MemoryRange::mmap(base, PageSize(), PROT_NONE,
   1.665 +                                  MAP_PRIVATE | MAP_ANONYMOUS, -1, 0));
   1.666 +  if (mem == base) {
   1.667 +    /* If program headers aren't mapped, try to map them */
   1.668 +    int fd = open("/proc/self/exe", O_RDONLY);
   1.669 +    if (fd == -1) {
   1.670 +      DEBUG_LOG("Failed to open /proc/self/exe");
   1.671 +      return;
   1.672 +    }
   1.673 +    mem.Assign(MemoryRange::mmap(base, PageSize(), PROT_READ, MAP_PRIVATE,
   1.674 +                                 fd, 0));
   1.675 +    /* If we don't manage to map at the right address, just give up. */
   1.676 +    if (mem != base) {
   1.677 +      DEBUG_LOG("Couldn't read program headers");
   1.678 +      return;
   1.679 +    }
   1.680 +  }
   1.681 +  /* Sanity check: the first bytes at the base address should be an ELF
   1.682 +   * header. */
   1.683 +  if (!Elf::Ehdr::validate(base)) {
   1.684 +     DEBUG_LOG("Couldn't find program base");
   1.685 +     return;
   1.686 +  }
   1.687 +
   1.688 +  /* Search for the program PT_DYNAMIC segment */
   1.689 +  Array<Elf::Dyn> dyns;
   1.690 +  for (Array<Elf::Phdr>::iterator phdr = phdrs.begin(); phdr < phdrs.end();
   1.691 +       ++phdr) {
   1.692 +    /* While the program headers are expected within the first mapped page of
   1.693 +     * the program executable, the executable PT_LOADs may actually make them
   1.694 +     * loaded at an address that is not the wanted base address of the
   1.695 +     * library. We thus need to adjust the base address, compensating for the
   1.696 +     * virtual address of the PT_LOAD segment corresponding to offset 0. */
   1.697 +    if (phdr->p_type == PT_LOAD && phdr->p_offset == 0)
   1.698 +      base -= phdr->p_vaddr;
   1.699 +    if (phdr->p_type == PT_DYNAMIC)
   1.700 +      dyns.Init(base + phdr->p_vaddr, phdr->p_filesz);
   1.701 +  }
   1.702 +  if (!dyns) {
   1.703 +    DEBUG_LOG("Failed to find PT_DYNAMIC section in program");
   1.704 +    return;
   1.705 +  }
   1.706 +
   1.707 +  /* Search for the DT_DEBUG information */
   1.708 +  for (Array<Elf::Dyn>::iterator dyn = dyns.begin(); dyn < dyns.end(); ++dyn) {
   1.709 +    if (dyn->d_tag == DT_DEBUG) {
   1.710 +      dbg = reinterpret_cast<r_debug *>(dyn->d_un.d_ptr);
   1.711 +      break;
   1.712 +    }
   1.713 +  }
   1.714 +  DEBUG_LOG("DT_DEBUG points at %p", static_cast<void *>(dbg));
   1.715 +}
   1.716 +
   1.717 +/**
   1.718 + * Helper class to ensure the given pointer is writable within the scope of
   1.719 + * an instance. Permissions to the memory page where the pointer lies are
   1.720 + * restored to their original value when the instance is destroyed.
   1.721 + */
   1.722 +class EnsureWritable
   1.723 +{
   1.724 +public:
   1.725 +  template <typename T>
   1.726 +  EnsureWritable(T *ptr, size_t length_ = sizeof(T))
   1.727 +  {
   1.728 +    MOZ_ASSERT(length_ < PageSize());
   1.729 +    prot = -1;
   1.730 +    page = MAP_FAILED;
   1.731 +
   1.732 +    char *firstPage = PageAlignedPtr(reinterpret_cast<char *>(ptr));
   1.733 +    char *lastPageEnd = PageAlignedEndPtr(reinterpret_cast<char *>(ptr) + length_);
   1.734 +    length = lastPageEnd - firstPage;
   1.735 +    uintptr_t start = reinterpret_cast<uintptr_t>(firstPage);
   1.736 +    uintptr_t end;
   1.737 +
   1.738 +    prot = getProt(start, &end);
   1.739 +    if (prot == -1 || (start + length) > end)
   1.740 +      MOZ_CRASH();
   1.741 +
   1.742 +    if (prot & PROT_WRITE)
   1.743 +      return;
   1.744 +
   1.745 +    page = firstPage;
   1.746 +    mprotect(page, length, prot | PROT_WRITE);
   1.747 +  }
   1.748 +
   1.749 +  ~EnsureWritable()
   1.750 +  {
   1.751 +    if (page != MAP_FAILED) {
   1.752 +      mprotect(page, length, prot);
   1.753 +}
   1.754 +  }
   1.755 +
   1.756 +private:
   1.757 +  int getProt(uintptr_t addr, uintptr_t *end)
   1.758 +  {
   1.759 +    /* The interesting part of the /proc/self/maps format looks like:
   1.760 +     * startAddr-endAddr rwxp */
   1.761 +    int result = 0;
   1.762 +    AutoCloseFILE f(fopen("/proc/self/maps", "r"));
   1.763 +    while (f) {
   1.764 +      unsigned long long startAddr, endAddr;
   1.765 +      char perms[5];
   1.766 +      if (fscanf(f, "%llx-%llx %4s %*1024[^\n] ", &startAddr, &endAddr, perms) != 3)
   1.767 +        return -1;
   1.768 +      if (addr < startAddr || addr >= endAddr)
   1.769 +        continue;
   1.770 +      if (perms[0] == 'r')
   1.771 +        result |= PROT_READ;
   1.772 +      else if (perms[0] != '-')
   1.773 +        return -1;
   1.774 +      if (perms[1] == 'w')
   1.775 +        result |= PROT_WRITE;
   1.776 +      else if (perms[1] != '-')
   1.777 +        return -1;
   1.778 +      if (perms[2] == 'x')
   1.779 +        result |= PROT_EXEC;
   1.780 +      else if (perms[2] != '-')
   1.781 +        return -1;
   1.782 +      *end = endAddr;
   1.783 +      return result;
   1.784 +    }
   1.785 +    return -1;
   1.786 +  }
   1.787 +
   1.788 +  int prot;
   1.789 +  void *page;
   1.790 +  size_t length;
   1.791 +};
   1.792 +
   1.793 +/**
   1.794 + * The system linker maintains a doubly linked list of library it loads
   1.795 + * for use by the debugger. Unfortunately, it also uses the list pointers
   1.796 + * in a lot of operations and adding our data in the list is likely to
   1.797 + * trigger crashes when the linker tries to use data we don't provide or
   1.798 + * that fall off the amount data we allocated. Fortunately, the linker only
   1.799 + * traverses the list forward and accesses the head of the list from a
   1.800 + * private pointer instead of using the value in the r_debug structure.
   1.801 + * This means we can safely add members at the beginning of the list.
   1.802 + * Unfortunately, gdb checks the coherency of l_prev values, so we have
   1.803 + * to adjust the l_prev value for the first element the system linker
   1.804 + * knows about. Fortunately, it doesn't use l_prev, and the first element
   1.805 + * is not ever going to be released before our elements, since it is the
   1.806 + * program executable, so the system linker should not be changing
   1.807 + * r_debug::r_map.
   1.808 + */
   1.809 +void
   1.810 +ElfLoader::DebuggerHelper::Add(ElfLoader::link_map *map)
   1.811 +{
   1.812 +  if (!dbg->r_brk)
   1.813 +    return;
   1.814 +  dbg->r_state = r_debug::RT_ADD;
   1.815 +  dbg->r_brk();
   1.816 +  map->l_prev = nullptr;
   1.817 +  map->l_next = dbg->r_map;
   1.818 +  if (!firstAdded) {
   1.819 +    firstAdded = map;
   1.820 +    /* When adding a library for the first time, r_map points to data
   1.821 +     * handled by the system linker, and that data may be read-only */
   1.822 +    EnsureWritable w(&dbg->r_map->l_prev);
   1.823 +    dbg->r_map->l_prev = map;
   1.824 +  } else
   1.825 +    dbg->r_map->l_prev = map;
   1.826 +  dbg->r_map = map;
   1.827 +  dbg->r_state = r_debug::RT_CONSISTENT;
   1.828 +  dbg->r_brk();
   1.829 +}
   1.830 +
   1.831 +void
   1.832 +ElfLoader::DebuggerHelper::Remove(ElfLoader::link_map *map)
   1.833 +{
   1.834 +  if (!dbg->r_brk)
   1.835 +    return;
   1.836 +  dbg->r_state = r_debug::RT_DELETE;
   1.837 +  dbg->r_brk();
   1.838 +  if (dbg->r_map == map)
   1.839 +    dbg->r_map = map->l_next;
   1.840 +  else
   1.841 +    map->l_prev->l_next = map->l_next;
   1.842 +  if (map == firstAdded) {
   1.843 +    firstAdded = map->l_prev;
   1.844 +    /* When removing the first added library, its l_next is going to be
   1.845 +     * data handled by the system linker, and that data may be read-only */
   1.846 +    EnsureWritable w(&map->l_next->l_prev);
   1.847 +    map->l_next->l_prev = map->l_prev;
   1.848 +  } else
   1.849 +    map->l_next->l_prev = map->l_prev;
   1.850 +  dbg->r_state = r_debug::RT_CONSISTENT;
   1.851 +  dbg->r_brk();
   1.852 +}
   1.853 +
   1.854 +#if defined(ANDROID)
   1.855 +/* As some system libraries may be calling signal() or sigaction() to
   1.856 + * set a SIGSEGV handler, effectively breaking MappableSeekableZStream,
   1.857 + * or worse, restore our SIGSEGV handler with wrong flags (which using
   1.858 + * signal() will do), we want to hook into the system's sigaction() to
   1.859 + * replace it with our own wrapper instead, so that our handler is never
   1.860 + * replaced. We used to only do that with libraries this linker loads,
   1.861 + * but it turns out at least one system library does call signal() and
   1.862 + * breaks us (libsc-a3xx.so on the Samsung Galaxy S4).
   1.863 + * As libc's signal (bsd_signal/sysv_signal, really) calls sigaction
   1.864 + * under the hood, instead of calling the signal system call directly,
   1.865 + * we only need to hook sigaction. This is true for both bionic and
   1.866 + * glibc.
   1.867 + */
   1.868 +
   1.869 +/* libc's sigaction */
   1.870 +extern "C" int
   1.871 +sigaction(int signum, const struct sigaction *act,
   1.872 +          struct sigaction *oldact);
   1.873 +
   1.874 +/* Simple reimplementation of sigaction. This is roughly equivalent
   1.875 + * to the assembly that comes in bionic, but not quite equivalent to
   1.876 + * glibc's implementation, so we only use this on Android. */
   1.877 +int
   1.878 +sys_sigaction(int signum, const struct sigaction *act,
   1.879 +              struct sigaction *oldact)
   1.880 +{
   1.881 +  return syscall(__NR_sigaction, signum, act, oldact);
   1.882 +}
   1.883 +
   1.884 +/* Replace the first instructions of the given function with a jump
   1.885 + * to the given new function. */
   1.886 +template <typename T>
   1.887 +static bool
   1.888 +Divert(T func, T new_func)
   1.889 +{
   1.890 +  void *ptr = FunctionPtr(func);
   1.891 +  uintptr_t addr = reinterpret_cast<uintptr_t>(ptr);
   1.892 +
   1.893 +#if defined(__i386__)
   1.894 +  // A 32-bit jump is a 5 bytes instruction.
   1.895 +  EnsureWritable w(ptr, 5);
   1.896 +  *reinterpret_cast<unsigned char *>(addr) = 0xe9; // jmp
   1.897 +  *reinterpret_cast<intptr_t *>(addr + 1) =
   1.898 +    reinterpret_cast<uintptr_t>(new_func) - addr - 5; // target displacement
   1.899 +  return true;
   1.900 +#elif defined(__arm__)
   1.901 +  const unsigned char trampoline[] = {
   1.902 +                            // .thumb
   1.903 +    0x46, 0x04,             // nop
   1.904 +    0x78, 0x47,             // bx pc
   1.905 +    0x46, 0x04,             // nop
   1.906 +                            // .arm
   1.907 +    0x04, 0xf0, 0x1f, 0xe5, // ldr pc, [pc, #-4]
   1.908 +                            // .word <new_func>
   1.909 +  };
   1.910 +  const unsigned char *start;
   1.911 +  if (addr & 0x01) {
   1.912 +    /* Function is thumb, the actual address of the code is without the
   1.913 +     * least significant bit. */
   1.914 +    addr--;
   1.915 +    /* The arm part of the trampoline needs to be 32-bit aligned */
   1.916 +    if (addr & 0x02)
   1.917 +      start = trampoline;
   1.918 +    else
   1.919 +      start = trampoline + 2;
   1.920 +  } else {
   1.921 +    /* Function is arm, we only need the arm part of the trampoline */
   1.922 +    start = trampoline + 6;
   1.923 +  }
   1.924 +
   1.925 +  size_t len = sizeof(trampoline) - (start - trampoline);
   1.926 +  EnsureWritable w(reinterpret_cast<void *>(addr), len + sizeof(void *));
   1.927 +  memcpy(reinterpret_cast<void *>(addr), start, len);
   1.928 +  *reinterpret_cast<void **>(addr + len) = FunctionPtr(new_func);
   1.929 +  cacheflush(addr, addr + len + sizeof(void *), 0);
   1.930 +  return true;
   1.931 +#else
   1.932 +  return false;
   1.933 +#endif
   1.934 +}
   1.935 +#else
   1.936 +#define sys_sigaction sigaction
   1.937 +template <typename T>
   1.938 +static bool
   1.939 +Divert(T func, T new_func)
   1.940 +{
   1.941 +  return false;
   1.942 +}
   1.943 +#endif
   1.944 +
   1.945 +namespace {
   1.946 +
   1.947 +/* Clock that only accounts for time spent in the current process. */
   1.948 +static uint64_t ProcessTimeStamp_Now()
   1.949 +{
   1.950 +  struct timespec ts;
   1.951 +  int rv = clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &ts);
   1.952 +
   1.953 +  if (rv != 0) {
   1.954 +    return 0;
   1.955 +  }
   1.956 +
   1.957 +  uint64_t baseNs = (uint64_t)ts.tv_sec * 1000000000;
   1.958 +  return baseNs + (uint64_t)ts.tv_nsec;
   1.959 +}
   1.960 +
   1.961 +}
   1.962 +
   1.963 +/* Data structure used to pass data to the temporary signal handler,
   1.964 + * as well as triggering a test crash. */
   1.965 +struct TmpData {
   1.966 +  volatile int crash_int;
   1.967 +  volatile uint64_t crash_timestamp;
   1.968 +};
   1.969 +
   1.970 +SEGVHandler::SEGVHandler()
   1.971 +: registeredHandler(false), signalHandlingBroken(false)
   1.972 +, signalHandlingSlow(false)
   1.973 +{
   1.974 +  /* Initialize oldStack.ss_flags to an invalid value when used to set
   1.975 +   * an alternative stack, meaning we haven't got information about the
   1.976 +   * original alternative stack and thus don't mean to restore it */
   1.977 +  oldStack.ss_flags = SS_ONSTACK;
   1.978 +  if (!Divert(sigaction, __wrap_sigaction))
   1.979 +    return;
   1.980 +
   1.981 +  /* Get the current segfault signal handler. */
   1.982 +  sys_sigaction(SIGSEGV, nullptr, &this->action);
   1.983 +
   1.984 +  /* Some devices don't provide useful information to their SIGSEGV handlers,
   1.985 +   * making it impossible for on-demand decompression to work. To check if
   1.986 +   * we're on such a device, setup a temporary handler and deliberately
   1.987 +   * trigger a segfault. The handler will set signalHandlingBroken if the
   1.988 +   * provided information is bogus.
   1.989 +   * Some other devices have a kernel option enabled that makes SIGSEGV handler
   1.990 +   * have an overhead so high that it affects how on-demand decompression
   1.991 +   * performs. The handler will also set signalHandlingSlow if the triggered
   1.992 +   * SIGSEGV took too much time. */
   1.993 +  struct sigaction action;
   1.994 +  action.sa_sigaction = &SEGVHandler::test_handler;
   1.995 +  sigemptyset(&action.sa_mask);
   1.996 +  action.sa_flags = SA_SIGINFO | SA_NODEFER;
   1.997 +  action.sa_restorer = nullptr;
   1.998 +  stackPtr.Assign(MemoryRange::mmap(nullptr, PageSize(),
   1.999 +                                    PROT_READ | PROT_WRITE,
  1.1000 +                                    MAP_PRIVATE | MAP_ANONYMOUS, -1, 0));
  1.1001 +  if (stackPtr.get() == MAP_FAILED)
  1.1002 +    return;
  1.1003 +  if (sys_sigaction(SIGSEGV, &action, nullptr))
  1.1004 +    return;
  1.1005 +
  1.1006 +  TmpData *data = reinterpret_cast<TmpData*>(stackPtr.get());
  1.1007 +  data->crash_timestamp = ProcessTimeStamp_Now();
  1.1008 +  mprotect(stackPtr, stackPtr.GetLength(), PROT_NONE);
  1.1009 +  data->crash_int = 123;
  1.1010 +  /* Restore the original segfault signal handler. */
  1.1011 +  sys_sigaction(SIGSEGV, &this->action, nullptr);
  1.1012 +  stackPtr.Assign(MAP_FAILED, 0);
  1.1013 +  if (signalHandlingBroken || signalHandlingSlow)
  1.1014 +    return;
  1.1015 +
  1.1016 +  /* Setup an alternative stack if the already existing one is not big
  1.1017 +   * enough, or if there is none. */
  1.1018 +  if (sigaltstack(nullptr, &oldStack) == 0) {
  1.1019 +    if (oldStack.ss_flags == SS_ONSTACK)
  1.1020 +      oldStack.ss_flags = 0;
  1.1021 +    if (!oldStack.ss_sp || oldStack.ss_size < stackSize) {
  1.1022 +      stackPtr.Assign(MemoryRange::mmap(nullptr, stackSize,
  1.1023 +                                        PROT_READ | PROT_WRITE,
  1.1024 +                                        MAP_PRIVATE | MAP_ANONYMOUS, -1, 0));
  1.1025 +      if (stackPtr.get() == MAP_FAILED)
  1.1026 +        return;
  1.1027 +      stack_t stack;
  1.1028 +      stack.ss_sp = stackPtr;
  1.1029 +      stack.ss_size = stackSize;
  1.1030 +      stack.ss_flags = 0;
  1.1031 +      if (sigaltstack(&stack, nullptr) != 0)
  1.1032 +        return;
  1.1033 +    }
  1.1034 +  }
  1.1035 +  /* Register our own handler, and store the already registered one in
  1.1036 +   * SEGVHandler's struct sigaction member */
  1.1037 +  action.sa_sigaction = &SEGVHandler::handler;
  1.1038 +  action.sa_flags = SA_SIGINFO | SA_NODEFER | SA_ONSTACK;
  1.1039 +  registeredHandler = !sys_sigaction(SIGSEGV, &action, nullptr);
  1.1040 +}
  1.1041 +
  1.1042 +SEGVHandler::~SEGVHandler()
  1.1043 +{
  1.1044 +  /* Restore alternative stack for signals */
  1.1045 +  if (oldStack.ss_flags != SS_ONSTACK)
  1.1046 +    sigaltstack(&oldStack, nullptr);
  1.1047 +  /* Restore original signal handler */
  1.1048 +  if (registeredHandler)
  1.1049 +    sys_sigaction(SIGSEGV, &this->action, nullptr);
  1.1050 +}
  1.1051 +
  1.1052 +/* Test handler for a deliberately triggered SIGSEGV that determines whether
  1.1053 + * useful information is provided to signal handlers, particularly whether
  1.1054 + * si_addr is filled in properly, and whether the segfault handler is called
  1.1055 + * quickly enough. */
  1.1056 +void SEGVHandler::test_handler(int signum, siginfo_t *info, void *context)
  1.1057 +{
  1.1058 +  SEGVHandler &that = ElfLoader::Singleton;
  1.1059 +  if (signum != SIGSEGV ||
  1.1060 +      info == nullptr || info->si_addr != that.stackPtr.get())
  1.1061 +    that.signalHandlingBroken = true;
  1.1062 +  mprotect(that.stackPtr, that.stackPtr.GetLength(), PROT_READ | PROT_WRITE);
  1.1063 +  TmpData *data = reinterpret_cast<TmpData*>(that.stackPtr.get());
  1.1064 +  uint64_t latency = ProcessTimeStamp_Now() - data->crash_timestamp;
  1.1065 +  DEBUG_LOG("SEGVHandler latency: %" PRIu64, latency);
  1.1066 +  /* See bug 886736 for timings on different devices, 150 µs is reasonably above
  1.1067 +   * the latency on "working" devices and seems to be reasonably fast to incur
  1.1068 +   * a huge overhead to on-demand decompression. */
  1.1069 +  if (latency > 150000)
  1.1070 +    that.signalHandlingSlow = true;
  1.1071 +}
  1.1072 +
  1.1073 +/* TODO: "properly" handle signal masks and flags */
  1.1074 +void SEGVHandler::handler(int signum, siginfo_t *info, void *context)
  1.1075 +{
  1.1076 +  //ASSERT(signum == SIGSEGV);
  1.1077 +  DEBUG_LOG("Caught segmentation fault @%p", info->si_addr);
  1.1078 +
  1.1079 +  /* Check whether we segfaulted in the address space of a CustomElf. We're
  1.1080 +   * only expecting that to happen as an access error. */
  1.1081 +  if (info->si_code == SEGV_ACCERR) {
  1.1082 +    mozilla::RefPtr<LibHandle> handle =
  1.1083 +      ElfLoader::Singleton.GetHandleByPtr(info->si_addr);
  1.1084 +    if (handle && !handle->IsSystemElf()) {
  1.1085 +      DEBUG_LOG("Within the address space of a CustomElf");
  1.1086 +      CustomElf *elf = static_cast<CustomElf *>(static_cast<LibHandle *>(handle));
  1.1087 +      if (elf->mappable->ensure(info->si_addr))
  1.1088 +        return;
  1.1089 +    }
  1.1090 +  }
  1.1091 +
  1.1092 +  /* Redispatch to the registered handler */
  1.1093 +  SEGVHandler &that = ElfLoader::Singleton;
  1.1094 +  if (that.action.sa_flags & SA_SIGINFO) {
  1.1095 +    DEBUG_LOG("Redispatching to registered handler @%p",
  1.1096 +              FunctionPtr(that.action.sa_sigaction));
  1.1097 +    that.action.sa_sigaction(signum, info, context);
  1.1098 +  } else if (that.action.sa_handler == SIG_DFL) {
  1.1099 +    DEBUG_LOG("Redispatching to default handler");
  1.1100 +    /* Reset the handler to the default one, and trigger it. */
  1.1101 +    sys_sigaction(signum, &that.action, nullptr);
  1.1102 +    raise(signum);
  1.1103 +  } else if (that.action.sa_handler != SIG_IGN) {
  1.1104 +    DEBUG_LOG("Redispatching to registered handler @%p",
  1.1105 +              FunctionPtr(that.action.sa_handler));
  1.1106 +    that.action.sa_handler(signum);
  1.1107 +  } else {
  1.1108 +    DEBUG_LOG("Ignoring");
  1.1109 +  }
  1.1110 +}
  1.1111 +
  1.1112 +int
  1.1113 +SEGVHandler::__wrap_sigaction(int signum, const struct sigaction *act,
  1.1114 +                              struct sigaction *oldact)
  1.1115 +{
  1.1116 +  SEGVHandler &that = ElfLoader::Singleton;
  1.1117 +
  1.1118 +  /* Use system sigaction() function for all but SIGSEGV signals. */
  1.1119 +  if (!that.registeredHandler || (signum != SIGSEGV))
  1.1120 +    return sys_sigaction(signum, act, oldact);
  1.1121 +
  1.1122 +  if (oldact)
  1.1123 +    *oldact = that.action;
  1.1124 +  if (act)
  1.1125 +    that.action = *act;
  1.1126 +  return 0;
  1.1127 +}
  1.1128 +
  1.1129 +Logging Logging::Singleton;

mercurial