diff options
author | Christopher Ferris <cferris@google.com> | 2017-08-30 13:15:19 -0700 |
---|---|---|
committer | Christopher Ferris <cferris@google.com> | 2017-08-30 15:50:11 -0700 |
commit | 3f805ac3f8e61489f66a54bbdb1a8dd541c043d1 (patch) | |
tree | 5392038e32942faed35a0b94fd821e3dc3c887fe /libunwindstack/tests/MapInfoCreateMemoryTest.cpp | |
parent | e1f9a58c8649136af7578b01c3f224ea4b88b555 (diff) |
Add proper support for embedded elf files.
- Add a method to get the max size of an elf file by reading the
section header offset + size. This will properly map an elf
file embedded into an apk, instead of just mapping in what is done
by the dynamic linker. It does assume that the section headers are
at the end of the elf file.
- Add new tests for the above functionality.
- Update the unwind_symbols tool to take an address for finding a
function instead of dumping the entire symbol table.
Bug: 23762183
Test: Unit tests pass, unwind through the camera process and verify
Test: the GoogleCamera.apk shows some function names.
Change-Id: I00c021680fe1d43b60d652bf91bbf6667d9617be
Diffstat (limited to 'libunwindstack/tests/MapInfoCreateMemoryTest.cpp')
-rw-r--r-- | libunwindstack/tests/MapInfoCreateMemoryTest.cpp | 84 |
1 files changed, 71 insertions, 13 deletions
diff --git a/libunwindstack/tests/MapInfoCreateMemoryTest.cpp b/libunwindstack/tests/MapInfoCreateMemoryTest.cpp index 9e45e7812..2aab9c652 100644 --- a/libunwindstack/tests/MapInfoCreateMemoryTest.cpp +++ b/libunwindstack/tests/MapInfoCreateMemoryTest.cpp @@ -38,30 +38,50 @@ namespace unwindstack { class MapInfoCreateMemoryTest : public ::testing::Test { protected: + template <typename Ehdr, typename Shdr> + static void InitElf(int fd, uint64_t file_offset, uint64_t sh_offset, uint8_t class_type) { + std::vector<uint8_t> buffer(20000); + memset(buffer.data(), 0, buffer.size()); + + Ehdr ehdr; + memset(&ehdr, 0, sizeof(ehdr)); + memcpy(ehdr.e_ident, ELFMAG, SELFMAG); + ehdr.e_ident[EI_CLASS] = class_type; + ehdr.e_shoff = sh_offset; + ehdr.e_shentsize = sizeof(Shdr) + 100; + ehdr.e_shnum = 4; + memcpy(&buffer[file_offset], &ehdr, sizeof(ehdr)); + + ASSERT_TRUE(android::base::WriteFully(fd, buffer.data(), buffer.size())); + } + static void SetUpTestCase() { std::vector<uint8_t> buffer(1024); + memset(buffer.data(), 0, buffer.size()); memcpy(buffer.data(), ELFMAG, SELFMAG); - for (size_t i = SELFMAG; i < buffer.size(); i++) { - buffer[i] = i / 256 + 1; - } + buffer[EI_CLASS] = ELFCLASS32; ASSERT_TRUE(android::base::WriteFully(elf_.fd, buffer.data(), buffer.size())); - for (size_t i = 0; i < 0x100; i++) { - buffer[i] = i / 256 + 1; - } + memset(buffer.data(), 0, buffer.size()); memcpy(&buffer[0x100], ELFMAG, SELFMAG); - for (size_t i = 0x100 + SELFMAG; i < buffer.size(); i++) { - buffer[i] = i / 256 + 1; - } + buffer[0x100 + EI_CLASS] = ELFCLASS64; ASSERT_TRUE(android::base::WriteFully(elf_at_100_.fd, buffer.data(), buffer.size())); + + InitElf<Elf32_Ehdr, Elf32_Shdr>(elf32_at_map_.fd, 0x1000, 0x2000, ELFCLASS32); + InitElf<Elf64_Ehdr, Elf64_Shdr>(elf64_at_map_.fd, 0x2000, 0x3000, ELFCLASS64); } static TemporaryFile elf_; static TemporaryFile elf_at_100_; + + static TemporaryFile elf32_at_map_; + static TemporaryFile elf64_at_map_; }; TemporaryFile MapInfoCreateMemoryTest::elf_; TemporaryFile MapInfoCreateMemoryTest::elf_at_100_; +TemporaryFile MapInfoCreateMemoryTest::elf32_at_map_; +TemporaryFile MapInfoCreateMemoryTest::elf64_at_map_; TEST_F(MapInfoCreateMemoryTest, end_le_start) { MapInfo info{.start = 0x100, .end = 0x100, .offset = 0, .name = elf_.path}; @@ -93,8 +113,9 @@ TEST_F(MapInfoCreateMemoryTest, file_backed_non_zero_offset_full_file) { std::vector<uint8_t> buffer(1024); ASSERT_TRUE(memory->Read(0, buffer.data(), 1024)); ASSERT_TRUE(memcmp(buffer.data(), ELFMAG, SELFMAG) == 0); - for (size_t i = SELFMAG; i < buffer.size(); i++) { - ASSERT_EQ(i / 256 + 1, buffer[i]) << "Failed at byte " << i; + ASSERT_EQ(ELFCLASS32, buffer[EI_CLASS]); + for (size_t i = EI_CLASS + 1; i < buffer.size(); i++) { + ASSERT_EQ(0, buffer[i]) << "Failed at byte " << i; } ASSERT_FALSE(memory->Read(1024, buffer.data(), 1)); @@ -113,13 +134,50 @@ TEST_F(MapInfoCreateMemoryTest, file_backed_non_zero_offset_partial_file) { std::vector<uint8_t> buffer(0x100); ASSERT_TRUE(memory->Read(0, buffer.data(), 0x100)); ASSERT_TRUE(memcmp(buffer.data(), ELFMAG, SELFMAG) == 0); - for (size_t i = SELFMAG; i < buffer.size(); i++) { - ASSERT_EQ(2, buffer[i]) << "Failed at byte " << i; + ASSERT_EQ(ELFCLASS64, buffer[EI_CLASS]); + for (size_t i = EI_CLASS + 1; i < buffer.size(); i++) { + ASSERT_EQ(0, buffer[i]) << "Failed at byte " << i; } ASSERT_FALSE(memory->Read(0x100, buffer.data(), 1)); } +// Verify that if the offset is non-zero and there is an elf at that +// offset, that only part of the file is used. Further verify that if the +// embedded elf is bigger than the initial map, the new object is larger +// than the original map size. Do this for a 32 bit elf and a 64 bit elf. +TEST_F(MapInfoCreateMemoryTest, file_backed_non_zero_offset_partial_file_whole_elf32) { + MapInfo info{.start = 0x5000, .end = 0x6000, .offset = 0x1000, .name = elf32_at_map_.path}; + + std::unique_ptr<Memory> memory(info.CreateMemory(getpid())); + ASSERT_TRUE(memory.get() != nullptr); + ASSERT_EQ(0U, info.elf_offset); + + // Verify the memory is a valid elf. + uint8_t e_ident[SELFMAG + 1]; + ASSERT_TRUE(memory->Read(0, e_ident, SELFMAG)); + ASSERT_EQ(0, memcmp(e_ident, ELFMAG, SELFMAG)); + + // Read past the end of what would normally be the size of the map. + ASSERT_TRUE(memory->Read(0x1000, e_ident, 1)); +} + +TEST_F(MapInfoCreateMemoryTest, file_backed_non_zero_offset_partial_file_whole_elf64) { + MapInfo info{.start = 0x7000, .end = 0x8000, .offset = 0x2000, .name = elf64_at_map_.path}; + + std::unique_ptr<Memory> memory(info.CreateMemory(getpid())); + ASSERT_TRUE(memory.get() != nullptr); + ASSERT_EQ(0U, info.elf_offset); + + // Verify the memory is a valid elf. + uint8_t e_ident[SELFMAG + 1]; + ASSERT_TRUE(memory->Read(0, e_ident, SELFMAG)); + ASSERT_EQ(0, memcmp(e_ident, ELFMAG, SELFMAG)); + + // Read past the end of what would normally be the size of the map. + ASSERT_TRUE(memory->Read(0x1000, e_ident, 1)); +} + // Verify that device file names will never result in Memory object creation. TEST_F(MapInfoCreateMemoryTest, check_device_maps) { // Set up some memory so that a valid local memory object would |