Init .gnu_debugdata in GetElf().

- Modify the tests to share some code for the generation of the elf data.
- Move the gnu_debugdata files into a separate directory.
- Add tests for GetElf().
- Move the CreateMemory() tests and the GetElf() tests into separate files.

Bug: 23762183

Test: New unit tests pass.
Change-Id: Ie3380296bb49753c2ac8801cfa11f93d6ff7121d
This commit is contained in:
Christopher Ferris 2017-06-30 17:18:16 -07:00
parent 67897d47ce
commit 570b76f04f
9 changed files with 366 additions and 205 deletions

View file

@ -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",
],
}

View file

@ -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;

View file

@ -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) {
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_);
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"));
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;
TestInitGnuDebugdata<Elf64_Ehdr, Elf64_Shdr>(ELFCLASS64, EM_AARCH64, false,
[&](uint64_t offset, const void* ptr, size_t size) {
memory_->SetMemory(offset, ptr, size);
});
GnuDebugdataInitFail<Elf64_Ehdr, Elf64_Shdr>(&ehdr);
}
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";
}
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));
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(0x200U, elf.interface()->gnu_debugdata_offset());
EXPECT_EQ(0x100U, elf.interface()->gnu_debugdata_size());
}
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(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);
});
GnuDebugdataInit<Elf64_Ehdr, Elf64_Shdr>(&ehdr);
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());
elf.InitGnuDebugdata();
ASSERT_TRUE(elf.gnu_debugdata_interface() != nullptr);
}

View file

@ -0,0 +1,129 @@
/*
* 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);

View file

@ -0,0 +1,31 @@
/*
* 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

View file

@ -34,7 +34,7 @@
#include "MapInfo.h"
#include "Memory.h"
class MapInfoTest : public ::testing::Test {
class MapInfoCreateMemoryTest : public ::testing::Test {
protected:
static void SetUpTestCase() {
std::vector<uint8_t> buffer(1024);
@ -58,10 +58,10 @@ class MapInfoTest : public ::testing::Test {
static TemporaryFile elf_at_100_;
};
TemporaryFile MapInfoTest::elf_;
TemporaryFile MapInfoTest::elf_at_100_;
TemporaryFile MapInfoCreateMemoryTest::elf_;
TemporaryFile MapInfoCreateMemoryTest::elf_at_100_;
TEST_F(MapInfoTest, end_le_start) {
TEST_F(MapInfoCreateMemoryTest, end_le_start) {
MapInfo info{.start = 0x100, .end = 0x100, .offset = 0, .name = elf_.path};
std::unique_ptr<Memory> memory;
@ -80,7 +80,7 @@ TEST_F(MapInfoTest, end_le_start) {
// Verify that if the offset is non-zero but there is no elf at the offset,
// that the full file is used.
TEST_F(MapInfoTest, create_memory_file_backed_non_zero_offset_full_file) {
TEST_F(MapInfoCreateMemoryTest, file_backed_non_zero_offset_full_file) {
MapInfo info{.start = 0x100, .end = 0x200, .offset = 0x100, .name = elf_.path};
std::unique_ptr<Memory> memory(info.CreateMemory(getpid()));
@ -100,7 +100,7 @@ TEST_F(MapInfoTest, create_memory_file_backed_non_zero_offset_full_file) {
// Verify that if the offset is non-zero and there is an elf at that
// offset, that only part of the file is used.
TEST_F(MapInfoTest, create_memory_file_backed_non_zero_offset_partial_file) {
TEST_F(MapInfoCreateMemoryTest, file_backed_non_zero_offset_partial_file) {
MapInfo info{.start = 0x100, .end = 0x200, .offset = 0x100, .name = elf_at_100_.path};
std::unique_ptr<Memory> memory(info.CreateMemory(getpid()));
@ -119,7 +119,7 @@ TEST_F(MapInfoTest, create_memory_file_backed_non_zero_offset_partial_file) {
}
// Verify that device file names will never result in Memory object creation.
TEST_F(MapInfoTest, create_memory_check_device_maps) {
TEST_F(MapInfoCreateMemoryTest, check_device_maps) {
// Set up some memory so that a valid local memory object would
// be returned if the file mapping fails, but the device check is incorrect.
std::vector<uint8_t> buffer(1024);
@ -135,7 +135,7 @@ TEST_F(MapInfoTest, create_memory_check_device_maps) {
ASSERT_TRUE(memory.get() == nullptr);
}
TEST_F(MapInfoTest, create_memory_local_memory) {
TEST_F(MapInfoCreateMemoryTest, local_memory) {
// Set up some memory for a valid local memory object.
std::vector<uint8_t> buffer(1024);
for (size_t i = 0; i < buffer.size(); i++) {
@ -160,7 +160,7 @@ TEST_F(MapInfoTest, create_memory_local_memory) {
ASSERT_FALSE(memory->Read(read_buffer.size(), read_buffer.data(), 1));
}
TEST_F(MapInfoTest, create_memory_remote_memory) {
TEST_F(MapInfoCreateMemoryTest, remote_memory) {
std::vector<uint8_t> buffer(1024);
memset(buffer.data(), 0xa, buffer.size());
@ -202,19 +202,3 @@ TEST_F(MapInfoTest, create_memory_remote_memory) {
kill(pid, SIGKILL);
}
TEST_F(MapInfoTest, get_elf) {
// Create a map to use as initialization data.
void* map = mmap(nullptr, 1024, PROT_READ, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
ASSERT_NE(MAP_FAILED, map);
uint64_t start = reinterpret_cast<uint64_t>(map);
MapInfo info{.start = start, .end = start + 1024, .offset = 0, .name = ""};
// The map contains garbage, but this should still produce an elf object.
std::unique_ptr<Elf> elf(info.GetElf(getpid(), false));
ASSERT_TRUE(elf.get() != nullptr);
ASSERT_FALSE(elf->valid());
ASSERT_EQ(0, munmap(map, 1024));
}

View file

@ -0,0 +1,140 @@
/*
* 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 <signal.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/ptrace.h>
#include <sys/types.h>
#include <unistd.h>
#include <memory>
#include <vector>
#include <android-base/file.h>
#include <android-base/test_utils.h>
#include <gtest/gtest.h>
#include "Elf.h"
#include "ElfTestUtils.h"
#include "MapInfo.h"
class MapInfoGetElfTest : public ::testing::Test {
protected:
void SetUp() override {
map_ = mmap(nullptr, kMapSize, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
ASSERT_NE(MAP_FAILED, map_);
uint64_t start = reinterpret_cast<uint64_t>(map_);
info_.reset(new MapInfo{.start = start, .end = start + 1024, .offset = 0, .name = ""});
}
void TearDown() override { munmap(map_, kMapSize); }
const size_t kMapSize = 4096;
void* map_ = nullptr;
std::unique_ptr<MapInfo> info_;
};
TEST_F(MapInfoGetElfTest, invalid) {
// The map is empty, but this should still create an invalid elf object.
std::unique_ptr<Elf> elf(info_->GetElf(getpid(), false));
ASSERT_TRUE(elf.get() != nullptr);
ASSERT_FALSE(elf->valid());
}
TEST_F(MapInfoGetElfTest, valid32) {
Elf32_Ehdr ehdr;
TestInitEhdr<Elf32_Ehdr>(&ehdr, ELFCLASS32, EM_ARM);
memcpy(map_, &ehdr, sizeof(ehdr));
std::unique_ptr<Elf> elf(info_->GetElf(getpid(), false));
ASSERT_TRUE(elf.get() != nullptr);
ASSERT_TRUE(elf->valid());
EXPECT_EQ(static_cast<uint32_t>(EM_ARM), elf->machine_type());
EXPECT_EQ(ELFCLASS32, elf->class_type());
}
TEST_F(MapInfoGetElfTest, valid64) {
Elf64_Ehdr ehdr;
TestInitEhdr<Elf64_Ehdr>(&ehdr, ELFCLASS64, EM_AARCH64);
memcpy(map_, &ehdr, sizeof(ehdr));
std::unique_ptr<Elf> elf(info_->GetElf(getpid(), false));
ASSERT_TRUE(elf.get() != nullptr);
ASSERT_TRUE(elf->valid());
EXPECT_EQ(static_cast<uint32_t>(EM_AARCH64), elf->machine_type());
EXPECT_EQ(ELFCLASS64, elf->class_type());
}
TEST_F(MapInfoGetElfTest, gnu_debugdata_do_not_init32) {
TestInitGnuDebugdata<Elf32_Ehdr, Elf32_Shdr>(
ELFCLASS32, EM_ARM, false, [&](uint64_t offset, const void* ptr, size_t size) {
memcpy(&reinterpret_cast<uint8_t*>(map_)[offset], ptr, size);
});
std::unique_ptr<Elf> elf(info_->GetElf(getpid(), false));
ASSERT_TRUE(elf.get() != nullptr);
ASSERT_TRUE(elf->valid());
EXPECT_EQ(static_cast<uint32_t>(EM_ARM), elf->machine_type());
EXPECT_EQ(ELFCLASS32, elf->class_type());
EXPECT_TRUE(elf->gnu_debugdata_interface() == nullptr);
}
TEST_F(MapInfoGetElfTest, gnu_debugdata_do_not_init64) {
TestInitGnuDebugdata<Elf64_Ehdr, Elf64_Shdr>(
ELFCLASS64, EM_AARCH64, false, [&](uint64_t offset, const void* ptr, size_t size) {
memcpy(&reinterpret_cast<uint8_t*>(map_)[offset], ptr, size);
});
std::unique_ptr<Elf> elf(info_->GetElf(getpid(), false));
ASSERT_TRUE(elf.get() != nullptr);
ASSERT_TRUE(elf->valid());
EXPECT_EQ(static_cast<uint32_t>(EM_AARCH64), elf->machine_type());
EXPECT_EQ(ELFCLASS64, elf->class_type());
EXPECT_TRUE(elf->gnu_debugdata_interface() == nullptr);
}
TEST_F(MapInfoGetElfTest, gnu_debugdata_init32) {
TestInitGnuDebugdata<Elf32_Ehdr, Elf32_Shdr>(
ELFCLASS32, EM_ARM, true, [&](uint64_t offset, const void* ptr, size_t size) {
memcpy(&reinterpret_cast<uint8_t*>(map_)[offset], ptr, size);
});
std::unique_ptr<Elf> elf(info_->GetElf(getpid(), true));
ASSERT_TRUE(elf.get() != nullptr);
ASSERT_TRUE(elf->valid());
EXPECT_EQ(static_cast<uint32_t>(EM_ARM), elf->machine_type());
EXPECT_EQ(ELFCLASS32, elf->class_type());
EXPECT_TRUE(elf->gnu_debugdata_interface() != nullptr);
}
TEST_F(MapInfoGetElfTest, gnu_debugdata_init64) {
TestInitGnuDebugdata<Elf64_Ehdr, Elf64_Shdr>(
ELFCLASS64, EM_AARCH64, true, [&](uint64_t offset, const void* ptr, size_t size) {
memcpy(&reinterpret_cast<uint8_t*>(map_)[offset], ptr, size);
});
std::unique_ptr<Elf> elf(info_->GetElf(getpid(), true));
ASSERT_TRUE(elf.get() != nullptr);
ASSERT_TRUE(elf->valid());
EXPECT_EQ(static_cast<uint32_t>(EM_AARCH64), elf->machine_type());
EXPECT_EQ(ELFCLASS64, elf->class_type());
EXPECT_TRUE(elf->gnu_debugdata_interface() != nullptr);
}