Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 863fcdb0 authored by Christopher Ferris's avatar Christopher Ferris Committed by android-build-merger
Browse files

Merge "Add proper support for embedded elf files."

am: 537c68c8

Change-Id: Ia28dbb1bbd02d54602a6256295cccf2def9caf04
parents 39088d35 537c68c8
Loading
Loading
Loading
Loading
+22 −0
Original line number Diff line number Diff line
@@ -124,6 +124,28 @@ bool Elf::IsValidElf(Memory* memory) {
  return true;
}

void Elf::GetInfo(Memory* memory, bool* valid, uint64_t* size) {
  if (!IsValidElf(memory)) {
    *valid = false;
    return;
  }
  *size = 0;
  *valid = true;

  // Now read the section header information.
  uint8_t class_type;
  if (!memory->Read(EI_CLASS, &class_type, 1)) {
    return;
  }
  if (class_type == ELFCLASS32) {
    ElfInterface32::GetMaxSize(memory, size);
  } else if (class_type == ELFCLASS64) {
    ElfInterface64::GetMaxSize(memory, size);
  } else {
    *valid = false;
  }
}

ElfInterface* Elf::CreateInterfaceFromMemory(Memory* memory) {
  if (!IsValidElf(memory)) {
    return nullptr;
+19 −0
Original line number Diff line number Diff line
@@ -370,6 +370,22 @@ bool ElfInterface::Step(uint64_t pc, Regs* regs, Memory* process_memory) {
  return false;
}

// This is an estimation of the size of the elf file using the location
// of the section headers and size. This assumes that the section headers
// are at the end of the elf file. If the elf has a load bias, the size
// will be too large, but this is acceptable.
template <typename EhdrType>
void ElfInterface::GetMaxSizeWithTemplate(Memory* memory, uint64_t* size) {
  EhdrType ehdr;
  if (!memory->Read(0, &ehdr, sizeof(ehdr))) {
    return;
  }
  if (ehdr.e_shnum == 0) {
    return;
  }
  *size = ehdr.e_shoff + ehdr.e_shentsize * ehdr.e_shnum;
}

// Instantiate all of the needed template functions.
template void ElfInterface::InitHeadersWithTemplate<uint32_t>();
template void ElfInterface::InitHeadersWithTemplate<uint64_t>();
@@ -391,4 +407,7 @@ template bool ElfInterface::GetFunctionNameWithTemplate<Elf32_Sym>(uint64_t, std
template bool ElfInterface::GetFunctionNameWithTemplate<Elf64_Sym>(uint64_t, std::string*,
                                                                   uint64_t*);

template void ElfInterface::GetMaxSizeWithTemplate<Elf32_Ehdr>(Memory*, uint64_t*);
template void ElfInterface::GetMaxSizeWithTemplate<Elf64_Ehdr>(Memory*, uint64_t*);

}  // namespace unwindstack
+53 −24
Original line number Diff line number Diff line
@@ -27,6 +27,55 @@

namespace unwindstack {

Memory* MapInfo::GetFileMemory() {
  std::unique_ptr<MemoryFileAtOffset> memory(new MemoryFileAtOffset);
  if (offset == 0) {
    if (memory->Init(name, 0)) {
      return memory.release();
    }
    return nullptr;
  }

  // There are two possibilities when the offset is non-zero.
  // - There is an elf file embedded in a file.
  // - The whole file is an elf file, and the offset needs to be saved.
  //
  // Map in just the part of the file for the map. If this is not
  // a valid elf, then reinit as if the whole file is an elf file.
  // If the offset is a valid elf, then determine the size of the map
  // and reinit to that size. This is needed because the dynamic linker
  // only maps in a portion of the original elf, and never the symbol
  // file data.
  uint64_t map_size = end - start;
  if (!memory->Init(name, offset, map_size)) {
    return nullptr;
  }

  bool valid;
  uint64_t max_size;
  Elf::GetInfo(memory.get(), &valid, &max_size);
  if (!valid) {
    // Init as if the whole file is an elf.
    if (memory->Init(name, 0)) {
      elf_offset = offset;
      return memory.release();
    }
    return nullptr;
  }

  if (max_size > map_size) {
    if (memory->Init(name, offset, max_size)) {
      return memory.release();
    }
    // Try to reinit using the default map_size.
    if (memory->Init(name, offset, map_size)) {
      return memory.release();
    }
    return nullptr;
  }
  return memory.release();
}

Memory* MapInfo::CreateMemory(pid_t pid) {
  if (end <= start) {
    return nullptr;
@@ -40,33 +89,13 @@ Memory* MapInfo::CreateMemory(pid_t pid) {
    if (flags & MAPS_FLAGS_DEVICE_MAP) {
      return nullptr;
    }

    std::unique_ptr<MemoryFileAtOffset> file_memory(new MemoryFileAtOffset);
    uint64_t map_size;
    if (offset != 0) {
      // Only map in a piece of the file.
      map_size = end - start;
    } else {
      map_size = UINT64_MAX;
    }
    if (file_memory->Init(name, offset, map_size)) {
      // It's possible that a non-zero offset might not be pointing to
      // valid elf data. Check if this is a valid elf, and if not assume
      // that this was meant to incorporate the entire file.
      if (offset != 0 && !Elf::IsValidElf(file_memory.get())) {
        // Don't bother checking the validity that will happen on the elf init.
        if (file_memory->Init(name, 0)) {
          elf_offset = offset;
          return file_memory.release();
        }
        // Fall through if the init fails.
      } else {
        return file_memory.release();
      }
    Memory* memory = GetFileMemory();
    if (memory != nullptr) {
      return memory;
    }
  }

  Memory* memory = nullptr;
  Memory* memory;
  if (pid == getpid()) {
    memory = new MemoryLocal();
  } else {
+2 −0
Original line number Diff line number Diff line
@@ -70,6 +70,8 @@ class Elf {

  static bool IsValidElf(Memory* memory);

  static void GetInfo(Memory* memory, bool* valid, uint64_t* size);

 protected:
  bool valid_ = false;
  std::unique_ptr<ElfInterface> interface_;
+11 −0
Original line number Diff line number Diff line
@@ -102,6 +102,9 @@ class ElfInterface {

  virtual bool HandleType(uint64_t, uint32_t) { return false; }

  template <typename EhdrType>
  static void GetMaxSizeWithTemplate(Memory* memory, uint64_t* size);

  Memory* memory_;
  std::unordered_map<uint64_t, LoadInfo> pt_loads_;
  uint64_t load_bias_ = 0;
@@ -146,6 +149,10 @@ class ElfInterface32 : public ElfInterface {
  bool GetFunctionName(uint64_t addr, std::string* name, uint64_t* func_offset) override {
    return ElfInterface::GetFunctionNameWithTemplate<Elf32_Sym>(addr, name, func_offset);
  }

  static void GetMaxSize(Memory* memory, uint64_t* size) {
    GetMaxSizeWithTemplate<Elf32_Ehdr>(memory, size);
  }
};

class ElfInterface64 : public ElfInterface {
@@ -166,6 +173,10 @@ class ElfInterface64 : public ElfInterface {
  bool GetFunctionName(uint64_t addr, std::string* name, uint64_t* func_offset) override {
    return ElfInterface::GetFunctionNameWithTemplate<Elf64_Sym>(addr, name, func_offset);
  }

  static void GetMaxSize(Memory* memory, uint64_t* size) {
    GetMaxSizeWithTemplate<Elf64_Ehdr>(memory, size);
  }
};

}  // namespace unwindstack
Loading