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

Commit 537c68c8 authored by Christopher Ferris's avatar Christopher Ferris Committed by Gerrit Code Review
Browse files

Merge "Add proper support for embedded elf files."

parents e1f9a58c 3f805ac3
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