author Andrew Halberstadt <>
Tue, 26 May 2015 10:12:51 -0400
changeset 249667 43e3ece52f5572b6a11b39d15d89eb4d6620a580
parent 245148 e9b68252df54c12015382d022f01e06c5605e27a
child 250786 c664375c0d5bed41821b4a9eaa298e3856efe1d2
permissions -rw-r--r--
Bug 1171602 - Run mochitest using mach from a, r=chmanchester

/* 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 */

#include "BaseElf.h"
#include "Elfxx.h"
#include "Logging.h"
#include "mozilla/RefPtr.h"

using namespace Elf;
using namespace mozilla;

unsigned long
BaseElf::Hash(const char *symbol)
  const unsigned char *sym = reinterpret_cast<const unsigned char *>(symbol);
  unsigned long h = 0, g;
  while (*sym) {
    h = (h << 4) + *sym++;
    g = h & 0xf0000000;
    h ^= g;
    h ^= g >> 24;
  return h;

void *
BaseElf::GetSymbolPtr(const char *symbol) const
  return GetSymbolPtr(symbol, Hash(symbol));

void *
BaseElf::GetSymbolPtr(const char *symbol, unsigned long hash) const
  const Sym *sym = GetSymbol(symbol, hash);
  void *ptr = nullptr;
  if (sym && sym->st_shndx != SHN_UNDEF)
    ptr = GetPtr(sym->st_value);
  DEBUG_LOG("BaseElf::GetSymbolPtr(%p [\"%s\"], \"%s\") = %p",
            reinterpret_cast<const void *>(this), GetPath(), symbol, ptr);
  return ptr;

const Sym *
BaseElf::GetSymbol(const char *symbol, unsigned long hash) const
  /* Search symbol with the buckets and chains tables.
   * The hash computed from the symbol name gives an index in the buckets
   * table. The corresponding value in the bucket table is an index in the
   * symbols table and in the chains table.
   * If the corresponding symbol in the symbols table matches, we're done.
   * Otherwise, the corresponding value in the chains table is a new index
   * in both tables, which corresponding symbol is tested and so on and so
   * forth */
  size_t bucket = hash % buckets.numElements();
  for (size_t y = buckets[bucket]; y != STN_UNDEF; y = chains[y]) {
    if (strcmp(symbol, strtab.GetStringAt(symtab[y].st_name)))
    return &symtab[y];
  return nullptr;

BaseElf::Contains(void *addr) const
  return base.Contains(addr);

#ifdef __ARM_EABI__
const void *
BaseElf::FindExidx(int *pcount) const
  if (arm_exidx) {
    *pcount = arm_exidx.numElements();
    return arm_exidx;
  *pcount = 0;
  return nullptr;

LoadedElf::Create(const char *path, void *base_addr)
  DEBUG_LOG("LoadedElf::Create(\"%s\", %p) = ...", path, base_addr);

  uint8_t mapped;
  /* If the page is not mapped, mincore returns an error. If base_addr is
   * nullptr, as would happen if the corresponding binary is prelinked with
   * the prelink look (but not with the android apriori tool), no page being
   * mapped there (right?), mincore returns an error, too, which makes
   * prelinked libraries on glibc unsupported. This is not an interesting
   * use case for now, so don't try supporting that case.
  if (mincore(const_cast<void*>(base_addr), PageSize(), &mapped))
    return nullptr;

  RefPtr<LoadedElf> elf = new LoadedElf(path);

  const Ehdr *ehdr = Ehdr::validate(base_addr);
  if (!ehdr)
    return nullptr;

  Addr min_vaddr = (Addr) -1; // We want to find the lowest and biggest
  Addr max_vaddr = 0;         // virtual address used by this Elf.
  const Phdr *dyn = nullptr;
#ifdef __ARM_EABI__
  const Phdr *arm_exidx_phdr = nullptr;

  Array<Phdr> phdrs(reinterpret_cast<const char *>(ehdr) + ehdr->e_phoff,
  for (auto phdr = phdrs.begin(); phdr < phdrs.end(); ++phdr) {
    switch (phdr->p_type) {
      case PT_LOAD:
        if (phdr->p_vaddr < min_vaddr)
          min_vaddr = phdr->p_vaddr;
        if (max_vaddr < phdr->p_vaddr + phdr->p_memsz)
          max_vaddr = phdr->p_vaddr + phdr->p_memsz;
      case PT_DYNAMIC:
        dyn = &*phdr;
#ifdef __ARM_EABI__
      case PT_ARM_EXIDX:
        /* We cannot initialize arm_exidx here
           because we don't have a base yet */
        arm_exidx_phdr = &*phdr;

  /* If the lowest PT_LOAD virtual address in headers is not 0, then the ELF
   * is either prelinked or a non-PIE executable. The former case is not
   * possible, because base_addr would be nullptr and the mincore test above
   * would already have made us return.
   * For a non-PIE executable, PT_LOADs contain absolute addresses, so in
   * practice, this means min_vaddr should be equal to base_addr. max_vaddr
   * can thus be adjusted accordingly.
  if (min_vaddr != 0) {
    void *min_vaddr_ptr = reinterpret_cast<void *>(
    if (min_vaddr_ptr != base_addr) {
      LOG("%s: %p != %p", elf->GetPath(), min_vaddr_ptr, base_addr);
      return nullptr;
    max_vaddr -= min_vaddr;
  if (!dyn) {
    LOG("%s: No PT_DYNAMIC segment found", elf->GetPath());
    return nullptr;

  elf->base.Assign(base_addr, max_vaddr);

  if (!elf->InitDyn(dyn))
    return nullptr;

#ifdef __ARM_EABI__
  if (arm_exidx_phdr)

  DEBUG_LOG("LoadedElf::Create(\"%s\", %p) = %p", path, base_addr,
    static_cast<void *>(elf));

  return elf.forget();

LoadedElf::InitDyn(const Phdr *pt_dyn)
  Array<Dyn> dyns;
  dyns.InitSize(GetPtr<Dyn>(pt_dyn->p_vaddr), pt_dyn->p_filesz);

  size_t symnum = 0;
  for (auto dyn = dyns.begin(); dyn < dyns.end() && dyn->d_tag; ++dyn) {
    switch (dyn->d_tag) {
      case DT_HASH:
          DEBUG_LOG("%s 0x%08" PRIxAddr, "DT_HASH", dyn->d_un.d_val);
          const Elf::Word *hash_table_header = \
          symnum = hash_table_header[1];
          buckets.Init(&hash_table_header[2], hash_table_header[0]);
      case DT_STRTAB:
        DEBUG_LOG("%s 0x%08" PRIxAddr, "DT_STRTAB", dyn->d_un.d_val);
      case DT_SYMTAB:
        DEBUG_LOG("%s 0x%08" PRIxAddr, "DT_SYMTAB", dyn->d_un.d_val);
  if (!buckets || !symnum) {
    ERROR("%s: Missing or broken DT_HASH", GetPath());
  } else if (!strtab) {
    ERROR("%s: Missing DT_STRTAB", GetPath());
  } else if (!symtab) {
    ERROR("%s: Missing DT_SYMTAB", GetPath());
  } else {
    return true;
  return false;