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

Commit 2d07f729 authored by Christopher Ferris's avatar Christopher Ferris Committed by Gerrit Code Review
Browse files

Merge "Init .gnu_debugdata in GetElf()."

parents f444650d 570b76f0
Loading
Loading
Loading
Loading
+5 −3
Original line number Diff line number Diff line
@@ -98,8 +98,10 @@ cc_defaults {
        "tests/ElfInterfaceArmTest.cpp",
        "tests/ElfInterfaceTest.cpp",
        "tests/ElfTest.cpp",
        "tests/ElfTestUtils.cpp",
        "tests/LogFake.cpp",
        "tests/MapInfoTest.cpp",
        "tests/MapInfoCreateMemoryTest.cpp",
        "tests/MapInfoGetElfTest.cpp",
        "tests/MapsTest.cpp",
        "tests/MemoryFake.cpp",
        "tests/MemoryFileTest.cpp",
@@ -144,8 +146,8 @@ cc_test {
    ],

    data: [
        "tests/elf32.xz",
        "tests/elf64.xz",
        "tests/files/elf32.xz",
        "tests/files/elf64.xz",
    ],
}

+4 −2
Original line number Diff line number Diff line
@@ -73,13 +73,15 @@ Memory* MapInfo::CreateMemory(pid_t pid) {
  return new MemoryRange(memory, start, end);
}

Elf* MapInfo::GetElf(pid_t pid, bool) {
Elf* MapInfo::GetElf(pid_t pid, bool init_gnu_debugdata) {
  if (elf) {
    return elf;
  }

  elf = new Elf(CreateMemory(pid));
  elf->Init();
  if (elf->Init() && init_gnu_debugdata) {
    elf->InitGnuDebugdata();
  }
  // If the init fails, keep the elf around as an invalid object so we
  // don't try to reinit the object.
  return elf;
+46 −173
Original line number Diff line number Diff line
@@ -24,6 +24,7 @@

#include "Elf.h"

#include "ElfTestUtils.h"
#include "MemoryFake.h"

#if !defined(PT_ARM_EXIDX)
@@ -36,36 +37,16 @@ class ElfTest : public ::testing::Test {
    memory_ = new MemoryFake;
  }

  template <typename Ehdr>
  void InitEhdr(Ehdr* ehdr) {
    memset(ehdr, 0, sizeof(Ehdr));
    memcpy(&ehdr->e_ident[0], ELFMAG, SELFMAG);
    ehdr->e_ident[EI_DATA] = ELFDATA2LSB;
    ehdr->e_ident[EI_VERSION] = EV_CURRENT;
    ehdr->e_ident[EI_OSABI] = ELFOSABI_SYSV;

    ehdr->e_type = ET_DYN;
    ehdr->e_version = EV_CURRENT;
  }

  void InitElf32(uint32_t machine) {
  void InitElf32(uint32_t machine_type) {
    Elf32_Ehdr ehdr;
    TestInitEhdr<Elf32_Ehdr>(&ehdr, ELFCLASS32, machine_type);

    InitEhdr<Elf32_Ehdr>(&ehdr);
    ehdr.e_ident[EI_CLASS] = ELFCLASS32;

    ehdr.e_machine = machine;
    ehdr.e_entry = 0;
    ehdr.e_phoff = 0x100;
    ehdr.e_shoff = 0;
    ehdr.e_flags = 0;
    ehdr.e_ehsize = sizeof(ehdr);
    ehdr.e_phentsize = sizeof(Elf32_Phdr);
    ehdr.e_phnum = 1;
    ehdr.e_shentsize = sizeof(Elf32_Shdr);
    ehdr.e_shnum = 0;
    ehdr.e_shstrndx = 0;
    if (machine == EM_ARM) {
    if (machine_type == EM_ARM) {
      ehdr.e_flags = 0x5000200;
      ehdr.e_phnum = 2;
    }
@@ -74,16 +55,13 @@ class ElfTest : public ::testing::Test {
    Elf32_Phdr phdr;
    memset(&phdr, 0, sizeof(phdr));
    phdr.p_type = PT_LOAD;
    phdr.p_offset = 0;
    phdr.p_vaddr = 0;
    phdr.p_paddr = 0;
    phdr.p_filesz = 0x10000;
    phdr.p_memsz = 0x10000;
    phdr.p_flags = PF_R | PF_X;
    phdr.p_align = 0x1000;
    memory_->SetMemory(0x100, &phdr, sizeof(phdr));

    if (machine == EM_ARM) {
    if (machine_type == EM_ARM) {
      memset(&phdr, 0, sizeof(phdr));
      phdr.p_type = PT_ARM_EXIDX;
      phdr.p_offset = 0x30000;
@@ -97,31 +75,21 @@ class ElfTest : public ::testing::Test {
    }
  }

  void InitElf64(uint32_t machine) {
  void InitElf64(uint32_t machine_type) {
    Elf64_Ehdr ehdr;
    TestInitEhdr<Elf64_Ehdr>(&ehdr, ELFCLASS64, machine_type);

    InitEhdr<Elf64_Ehdr>(&ehdr);
    ehdr.e_ident[EI_CLASS] = ELFCLASS64;

    ehdr.e_machine = machine;
    ehdr.e_entry = 0;
    ehdr.e_phoff = 0x100;
    ehdr.e_shoff = 0;
    ehdr.e_flags = 0x5000200;
    ehdr.e_ehsize = sizeof(ehdr);
    ehdr.e_phentsize = sizeof(Elf64_Phdr);
    ehdr.e_phnum = 1;
    ehdr.e_shentsize = sizeof(Elf64_Shdr);
    ehdr.e_shnum = 0;
    ehdr.e_shstrndx = 0;
    memory_->SetMemory(0, &ehdr, sizeof(ehdr));

    Elf64_Phdr phdr;
    memset(&phdr, 0, sizeof(phdr));
    phdr.p_type = PT_LOAD;
    phdr.p_offset = 0;
    phdr.p_vaddr = 0;
    phdr.p_paddr = 0;
    phdr.p_filesz = 0x10000;
    phdr.p_memsz = 0x10000;
    phdr.p_flags = PF_R | PF_X;
@@ -129,12 +97,6 @@ class ElfTest : public ::testing::Test {
    memory_->SetMemory(0x100, &phdr, sizeof(phdr));
  }

  template <typename Ehdr, typename Shdr>
  void GnuDebugdataInitFail(Ehdr* ehdr);

  template <typename Ehdr, typename Shdr>
  void GnuDebugdataInit(Ehdr* ehdr);

  MemoryFake* memory_;
};

@@ -214,153 +176,64 @@ TEST_F(ElfTest, elf_x86_64) {
  ASSERT_TRUE(elf.interface() != nullptr);
}

template <typename Ehdr, typename Shdr>
void ElfTest::GnuDebugdataInitFail(Ehdr* ehdr) {
  Elf elf(memory_);

  uint64_t offset = 0x2000;

  ehdr->e_shoff = offset;
  ehdr->e_shnum = 3;
  ehdr->e_shentsize = sizeof(Shdr);
  ehdr->e_shstrndx = 2;
  memory_->SetMemory(0, ehdr, sizeof(*ehdr));

  Shdr shdr;
  memset(&shdr, 0, sizeof(shdr));
  shdr.sh_type = SHT_NULL;
  memory_->SetMemory(offset, &shdr, sizeof(shdr));
  offset += ehdr->e_shentsize;

  memset(&shdr, 0, sizeof(shdr));
  shdr.sh_type = SHT_PROGBITS;
  shdr.sh_name = 0x100;
  shdr.sh_addr = 0x5000;
  shdr.sh_offset = 0x5000;
  shdr.sh_entsize = 0x100;
  shdr.sh_size = 0x800;
  memory_->SetMemory(offset, &shdr, sizeof(shdr));
  offset += ehdr->e_shentsize;

  memset(&shdr, 0, sizeof(shdr));
  shdr.sh_type = SHT_STRTAB;
  shdr.sh_name = 0x200000;
  shdr.sh_offset = 0xf000;
  shdr.sh_size = 0x1000;
  memory_->SetMemory(offset, &shdr, sizeof(shdr));
  offset += ehdr->e_shentsize;

  memory_->SetMemory(0xf100, ".gnu_debugdata", sizeof(".gnu_debugdata"));
TEST_F(ElfTest, gnu_debugdata_init_fail32) {
  TestInitGnuDebugdata<Elf32_Ehdr, Elf32_Shdr>(ELFCLASS32, EM_ARM, false,
                                               [&](uint64_t offset, const void* ptr, size_t size) {
                                                 memory_->SetMemory(offset, ptr, size);
                                               });

  Elf elf(memory_);
  ASSERT_TRUE(elf.Init());
  ASSERT_TRUE(elf.interface() != nullptr);
  ASSERT_TRUE(elf.gnu_debugdata_interface() == nullptr);
  EXPECT_EQ(0x5000U, elf.interface()->gnu_debugdata_offset());
  EXPECT_EQ(0x800U, elf.interface()->gnu_debugdata_size());

  elf.InitGnuDebugdata();
}

TEST_F(ElfTest, gnu_debugdata_init_fail32) {
  Elf32_Ehdr ehdr;
  InitEhdr<Elf32_Ehdr>(&ehdr);
  ehdr.e_ident[EI_CLASS] = ELFCLASS32;
  ehdr.e_machine = EM_ARM;

  GnuDebugdataInitFail<Elf32_Ehdr, Elf32_Shdr>(&ehdr);
  EXPECT_EQ(0x1acU, elf.interface()->gnu_debugdata_offset());
  EXPECT_EQ(0x100U, elf.interface()->gnu_debugdata_size());
}

TEST_F(ElfTest, gnu_debugdata_init_fail64) {
  Elf64_Ehdr ehdr;
  InitEhdr<Elf64_Ehdr>(&ehdr);
  ehdr.e_ident[EI_CLASS] = ELFCLASS64;
  ehdr.e_machine = EM_AARCH64;

  GnuDebugdataInitFail<Elf64_Ehdr, Elf64_Shdr>(&ehdr);
}
  TestInitGnuDebugdata<Elf64_Ehdr, Elf64_Shdr>(ELFCLASS64, EM_AARCH64, false,
                                               [&](uint64_t offset, const void* ptr, size_t size) {
                                                 memory_->SetMemory(offset, ptr, size);
                                               });

template <typename Ehdr, typename Shdr>
void ElfTest::GnuDebugdataInit(Ehdr* ehdr) {
  Elf elf(memory_);

  uint64_t offset = 0x2000;

  ehdr->e_shoff = offset;
  ehdr->e_shnum = 3;
  ehdr->e_shentsize = sizeof(Shdr);
  ehdr->e_shstrndx = 2;
  memory_->SetMemory(0, ehdr, sizeof(*ehdr));

  Shdr shdr;
  memset(&shdr, 0, sizeof(shdr));
  shdr.sh_type = SHT_NULL;
  memory_->SetMemory(offset, &shdr, sizeof(shdr));
  offset += ehdr->e_shentsize;

  uint64_t gnu_offset = offset;
  offset += ehdr->e_shentsize;

  memset(&shdr, 0, sizeof(shdr));
  shdr.sh_type = SHT_STRTAB;
  shdr.sh_name = 0x200000;
  shdr.sh_offset = 0xf000;
  shdr.sh_size = 0x1000;
  memory_->SetMemory(offset, &shdr, sizeof(shdr));
  offset += ehdr->e_shentsize;

  memory_->SetMemory(0xf100, ".gnu_debugdata", sizeof(".gnu_debugdata"));

  // Read in the compressed elf data and put it in our fake memory.
  std::string name("tests/");
  if (sizeof(Ehdr) == sizeof(Elf32_Ehdr)) {
    name += "elf32.xz";
  } else {
    name += "elf64.xz";
  ASSERT_TRUE(elf.Init());
  ASSERT_TRUE(elf.interface() != nullptr);
  ASSERT_TRUE(elf.gnu_debugdata_interface() == nullptr);
  EXPECT_EQ(0x200U, elf.interface()->gnu_debugdata_offset());
  EXPECT_EQ(0x100U, elf.interface()->gnu_debugdata_size());
}
  int fd = TEMP_FAILURE_RETRY(open(name.c_str(), O_RDONLY));
  ASSERT_NE(-1, fd) << "Cannot open " + name;
  // Assumes the file is less than 1024 bytes.
  std::vector<uint8_t> buf(1024);
  ssize_t bytes = TEMP_FAILURE_RETRY(read(fd, buf.data(), buf.size()));
  ASSERT_GT(bytes, 0);
  // Make sure the file isn't too big.
  ASSERT_NE(static_cast<size_t>(bytes), buf.size())
      << "File " + name + " is too big, increase buffer size.";
  close(fd);
  buf.resize(bytes);
  memory_->SetMemory(0x5000, buf);

  memset(&shdr, 0, sizeof(shdr));
  shdr.sh_type = SHT_PROGBITS;
  shdr.sh_name = 0x100;
  shdr.sh_addr = 0x5000;
  shdr.sh_offset = 0x5000;
  shdr.sh_size = bytes;
  memory_->SetMemory(gnu_offset, &shdr, sizeof(shdr));

TEST_F(ElfTest, gnu_debugdata_init32) {
  TestInitGnuDebugdata<Elf32_Ehdr, Elf32_Shdr>(ELFCLASS32, EM_ARM, true,
                                               [&](uint64_t offset, const void* ptr, size_t size) {
                                                 memory_->SetMemory(offset, ptr, size);
                                               });

  Elf elf(memory_);
  ASSERT_TRUE(elf.Init());
  ASSERT_TRUE(elf.interface() != nullptr);
  ASSERT_TRUE(elf.gnu_debugdata_interface() == nullptr);
  EXPECT_EQ(0x5000U, elf.interface()->gnu_debugdata_offset());
  EXPECT_EQ(0x1acU, elf.interface()->gnu_debugdata_offset());
  EXPECT_EQ(0x8cU, elf.interface()->gnu_debugdata_size());

  elf.InitGnuDebugdata();
  ASSERT_TRUE(elf.gnu_debugdata_interface() != nullptr);
}

TEST_F(ElfTest, gnu_debugdata_init32) {
  Elf32_Ehdr ehdr;
  InitEhdr<Elf32_Ehdr>(&ehdr);
  ehdr.e_ident[EI_CLASS] = ELFCLASS32;
  ehdr.e_machine = EM_ARM;

  GnuDebugdataInit<Elf32_Ehdr, Elf32_Shdr>(&ehdr);
}

TEST_F(ElfTest, gnu_debugdata_init64) {
  Elf64_Ehdr ehdr;
  InitEhdr<Elf64_Ehdr>(&ehdr);
  ehdr.e_ident[EI_CLASS] = ELFCLASS64;
  ehdr.e_machine = EM_AARCH64;
  TestInitGnuDebugdata<Elf64_Ehdr, Elf64_Shdr>(ELFCLASS64, EM_AARCH64, true,
                                               [&](uint64_t offset, const void* ptr, size_t size) {
                                                 memory_->SetMemory(offset, ptr, size);
                                               });

  Elf elf(memory_);
  ASSERT_TRUE(elf.Init());
  ASSERT_TRUE(elf.interface() != nullptr);
  ASSERT_TRUE(elf.gnu_debugdata_interface() == nullptr);
  EXPECT_EQ(0x200U, elf.interface()->gnu_debugdata_offset());
  EXPECT_EQ(0x90U, elf.interface()->gnu_debugdata_size());

  GnuDebugdataInit<Elf64_Ehdr, Elf64_Shdr>(&ehdr);
  elf.InitGnuDebugdata();
  ASSERT_TRUE(elf.gnu_debugdata_interface() != nullptr);
}
+129 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2016 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <elf.h>
#include <errno.h>
#include <fcntl.h>
#include <signal.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/ptrace.h>
#include <sys/types.h>
#include <unistd.h>

#include <string>
#include <vector>

#include <gtest/gtest.h>

#include "ElfTestUtils.h"

template <typename Ehdr>
void TestInitEhdr(Ehdr* ehdr, uint32_t elf_class, uint32_t machine_type) {
  memset(ehdr, 0, sizeof(Ehdr));
  memcpy(&ehdr->e_ident[0], ELFMAG, SELFMAG);
  ehdr->e_ident[EI_DATA] = ELFDATA2LSB;
  ehdr->e_ident[EI_VERSION] = EV_CURRENT;
  ehdr->e_ident[EI_OSABI] = ELFOSABI_SYSV;
  ehdr->e_ident[EI_CLASS] = elf_class;
  ehdr->e_type = ET_DYN;
  ehdr->e_machine = machine_type;
  ehdr->e_version = EV_CURRENT;
  ehdr->e_ehsize = sizeof(Ehdr);
}

template <typename Ehdr, typename Shdr>
void TestInitGnuDebugdata(uint32_t elf_class, uint32_t machine, bool init_gnu_debugdata,
                          TestCopyFuncType copy_func) {
  Ehdr ehdr;

  TestInitEhdr(&ehdr, elf_class, machine);

  uint64_t offset = sizeof(Ehdr);
  ehdr.e_shoff = offset;
  ehdr.e_shnum = 3;
  ehdr.e_shentsize = sizeof(Shdr);
  ehdr.e_shstrndx = 2;
  copy_func(0, &ehdr, sizeof(ehdr));

  Shdr shdr;
  memset(&shdr, 0, sizeof(shdr));
  shdr.sh_type = SHT_NULL;
  copy_func(offset, &shdr, sizeof(shdr));
  offset += ehdr.e_shentsize;

  // Skip this header, it will contain the gnu_debugdata information.
  uint64_t gnu_offset = offset;
  offset += ehdr.e_shentsize;

  uint64_t symtab_offset = sizeof(ehdr) + ehdr.e_shnum * ehdr.e_shentsize;
  memset(&shdr, 0, sizeof(shdr));
  shdr.sh_name = 1;
  shdr.sh_type = SHT_STRTAB;
  shdr.sh_offset = symtab_offset;
  shdr.sh_size = 0x100;
  copy_func(offset, &shdr, sizeof(shdr));

  char value = '\0';
  uint64_t symname_offset = symtab_offset;
  copy_func(symname_offset, &value, 1);
  symname_offset++;
  std::string name(".shstrtab");
  copy_func(symname_offset, name.c_str(), name.size() + 1);
  symname_offset += name.size() + 1;
  name = ".gnu_debugdata";
  copy_func(symname_offset, name.c_str(), name.size() + 1);

  ssize_t bytes = 0x100;
  offset = symtab_offset + 0x100;
  if (init_gnu_debugdata) {
    // Read in the compressed elf data and copy it in.
    name = "tests/files/";
    if (elf_class == ELFCLASS32) {
      name += "elf32.xz";
    } else {
      name += "elf64.xz";
    }
    int fd = TEMP_FAILURE_RETRY(open(name.c_str(), O_RDONLY));
    ASSERT_NE(-1, fd) << "Cannot open " + name;
    // Assumes the file is less than 1024 bytes.
    std::vector<uint8_t> buf(1024);
    bytes = TEMP_FAILURE_RETRY(read(fd, buf.data(), buf.size()));
    ASSERT_GT(bytes, 0);
    // Make sure the file isn't too big.
    ASSERT_NE(static_cast<size_t>(bytes), buf.size())
        << "File " + name + " is too big, increase buffer size.";
    close(fd);
    buf.resize(bytes);
    copy_func(offset, buf.data(), buf.size());
  }

  memset(&shdr, 0, sizeof(shdr));
  shdr.sh_type = SHT_PROGBITS;
  shdr.sh_name = symname_offset - symtab_offset;
  shdr.sh_addr = offset;
  shdr.sh_offset = offset;
  shdr.sh_size = bytes;
  copy_func(gnu_offset, &shdr, sizeof(shdr));
}

template void TestInitEhdr<Elf32_Ehdr>(Elf32_Ehdr*, uint32_t, uint32_t);
template void TestInitEhdr<Elf64_Ehdr>(Elf64_Ehdr*, uint32_t, uint32_t);

template void TestInitGnuDebugdata<Elf32_Ehdr, Elf32_Shdr>(uint32_t, uint32_t, bool,
                                                           TestCopyFuncType);
template void TestInitGnuDebugdata<Elf64_Ehdr, Elf64_Shdr>(uint32_t, uint32_t, bool,
                                                           TestCopyFuncType);
+31 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2017 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef _LIBUNWINDSTACK_TESTS_ELF_TEST_UTILS_H
#define _LIBUNWINDSTACK_TESTS_ELF_TEST_UTILS_H

#include <functional>

typedef std::function<void(uint64_t, const void*, size_t)> TestCopyFuncType;

template <typename Ehdr>
void TestInitEhdr(Ehdr* ehdr, uint32_t elf_class, uint32_t machine_type);

template <typename Ehdr, typename Shdr>
void TestInitGnuDebugdata(uint32_t elf_class, uint32_t machine_type, bool init_gnu_debudata,
                          TestCopyFuncType copy_func);

#endif  // _LIBUNWINDSTACK_TESTS_ELF_TEST_UTILS_H
Loading