diff options
author | Christopher Ferris <cferris@google.com> | 2017-09-01 11:17:16 -0700 |
---|---|---|
committer | Christopher Ferris <cferris@google.com> | 2017-09-05 14:30:22 -0700 |
commit | 5f118519fd323a0c71b54de9279e8a9ea6a56271 (patch) | |
tree | 3ce288c58ab8d5a6aa1d3c307def1f0f1019ae7a /libunwindstack | |
parent | 9638729a9d9e3cbbbe1bb2784e774fef0f2e6a54 (diff) | |
download | system_core-5f118519fd323a0c71b54de9279e8a9ea6a56271.tar.gz system_core-5f118519fd323a0c71b54de9279e8a9ea6a56271.tar.bz2 system_core-5f118519fd323a0c71b54de9279e8a9ea6a56271.zip |
Add a method to share the process memory object.
New function to create the process memory object. This allows for
a future where different remote process memory objects could be created
depending on the way remote memory can be created. Even different local
memory objects that access memory without doing any checks.
It also allows MemoryRange objects to share one single process memory object
and could help if the process memory object caches data.
Small changes to MapInfo::CreateMemory to when some errors are detected.
- Always check if the map is a device map, instead of only if the name
is not empty.
- Check if a memory map is readable before creating the memory from process
memory.
Bug: 23762183
Test: Ran unit tests, unwound on device using the new code.
Change-Id: I12a93c2dc19639689a528ec41c67bfac74d431b3
Diffstat (limited to 'libunwindstack')
-rw-r--r-- | libunwindstack/Android.bp | 8 | ||||
-rw-r--r-- | libunwindstack/MapInfo.cpp | 26 | ||||
-rw-r--r-- | libunwindstack/Memory.cpp | 9 | ||||
-rw-r--r-- | libunwindstack/include/unwindstack/MapInfo.h | 9 | ||||
-rw-r--r-- | libunwindstack/include/unwindstack/Memory.h | 9 | ||||
-rw-r--r-- | libunwindstack/tests/MapInfoCreateMemoryTest.cpp | 102 | ||||
-rw-r--r-- | libunwindstack/tests/MapInfoGetElfTest.cpp | 281 | ||||
-rw-r--r-- | libunwindstack/tests/MemoryRangeTest.cpp | 17 | ||||
-rw-r--r-- | libunwindstack/tests/UnwindTest.cpp | 19 | ||||
-rw-r--r-- | libunwindstack/tools/unwind.cpp | 6 |
10 files changed, 343 insertions, 143 deletions
diff --git a/libunwindstack/Android.bp b/libunwindstack/Android.bp index b971a9eda..78f674c9e 100644 --- a/libunwindstack/Android.bp +++ b/libunwindstack/Android.bp @@ -57,6 +57,13 @@ cc_library { "Symbols.cpp", ], + target: { + // Always disable optimizations for host to make it easier to debug. + linux: { + cflags: ["-O0", "-g"], + }, + }, + arch: { x86: { srcs: ["AsmGetRegsX86.S"], @@ -97,7 +104,6 @@ cc_test { "tests/ElfTest.cpp", "tests/ElfTestUtils.cpp", "tests/LogFake.cpp", - "tests/MapInfoCreateMemoryTest.cpp", "tests/MapInfoGetElfTest.cpp", "tests/MapsTest.cpp", "tests/MemoryBufferTest.cpp", diff --git a/libunwindstack/MapInfo.cpp b/libunwindstack/MapInfo.cpp index 32722154a..96f2cb42b 100644 --- a/libunwindstack/MapInfo.cpp +++ b/libunwindstack/MapInfo.cpp @@ -14,6 +14,7 @@ * limitations under the License. */ +#include <sys/mman.h> #include <sys/types.h> #include <unistd.h> @@ -76,40 +77,39 @@ Memory* MapInfo::GetFileMemory() { return memory.release(); } -Memory* MapInfo::CreateMemory(pid_t pid) { +Memory* MapInfo::CreateMemory(const std::shared_ptr<Memory>& process_memory) { if (end <= start) { return nullptr; } elf_offset = 0; + // Fail on device maps. + if (flags & MAPS_FLAGS_DEVICE_MAP) { + return nullptr; + } + // First try and use the file associated with the info. if (!name.empty()) { - // Fail on device maps. - if (flags & MAPS_FLAGS_DEVICE_MAP) { - return nullptr; - } Memory* memory = GetFileMemory(); if (memory != nullptr) { return memory; } } - Memory* memory; - if (pid == getpid()) { - memory = new MemoryLocal(); - } else { - memory = new MemoryRemote(pid); + // If the map isn't readable, don't bother trying to read from process memory. + if (!(flags & PROT_READ)) { + return nullptr; } - return new MemoryRange(memory, start, end); + return new MemoryRange(process_memory, start, end); } -Elf* MapInfo::GetElf(pid_t pid, bool init_gnu_debugdata) { +Elf* MapInfo::GetElf(const std::shared_ptr<Memory>& process_memory, bool init_gnu_debugdata) { if (elf) { return elf; } - elf = new Elf(CreateMemory(pid)); + elf = new Elf(CreateMemory(process_memory)); if (elf->Init() && init_gnu_debugdata) { elf->InitGnuDebugdata(); } diff --git a/libunwindstack/Memory.cpp b/libunwindstack/Memory.cpp index 8c36055c4..32753df6f 100644 --- a/libunwindstack/Memory.cpp +++ b/libunwindstack/Memory.cpp @@ -52,6 +52,13 @@ bool Memory::ReadString(uint64_t addr, std::string* string, uint64_t max_read) { return false; } +std::shared_ptr<Memory> Memory::CreateProcessMemory(pid_t pid) { + if (pid == getpid()) { + return std::shared_ptr<Memory>(new MemoryLocal()); + } + return std::shared_ptr<Memory>(new MemoryRemote(pid)); +} + bool MemoryBuffer::Read(uint64_t addr, void* dst, size_t size) { uint64_t last_read_byte; if (__builtin_add_overflow(size, addr, &last_read_byte)) { @@ -249,7 +256,7 @@ bool MemoryOffline::Read(uint64_t addr, void* dst, size_t size) { return true; } -MemoryRange::MemoryRange(Memory* memory, uint64_t begin, uint64_t end) +MemoryRange::MemoryRange(const std::shared_ptr<Memory>& memory, uint64_t begin, uint64_t end) : memory_(memory), begin_(begin), length_(end - begin) { CHECK(end > begin); } diff --git a/libunwindstack/include/unwindstack/MapInfo.h b/libunwindstack/include/unwindstack/MapInfo.h index b8ba92576..f108766cf 100644 --- a/libunwindstack/include/unwindstack/MapInfo.h +++ b/libunwindstack/include/unwindstack/MapInfo.h @@ -40,10 +40,13 @@ struct MapInfo { // instead of a portion of the file. uint64_t elf_offset; - Memory* GetFileMemory(); - Memory* CreateMemory(pid_t pid); // This function guarantees it will never return nullptr. - Elf* GetElf(pid_t pid, bool init_gnu_debugdata = false); + Elf* GetElf(const std::shared_ptr<Memory>& process_memory, bool init_gnu_debugdata = false); + + private: + Memory* GetFileMemory(); + + Memory* CreateMemory(const std::shared_ptr<Memory>& process_memory); }; } // namespace unwindstack diff --git a/libunwindstack/include/unwindstack/Memory.h b/libunwindstack/include/unwindstack/Memory.h index 0c0526616..183b8993a 100644 --- a/libunwindstack/include/unwindstack/Memory.h +++ b/libunwindstack/include/unwindstack/Memory.h @@ -21,6 +21,7 @@ #include <sys/types.h> #include <unistd.h> +#include <memory> #include <string> #include <vector> @@ -31,6 +32,8 @@ class Memory { Memory() = default; virtual ~Memory() = default; + static std::shared_ptr<Memory> CreateProcessMemory(pid_t pid); + virtual bool ReadString(uint64_t addr, std::string* string, uint64_t max_read = UINT64_MAX); virtual bool Read(uint64_t addr, void* dst, size_t size) = 0; @@ -125,13 +128,13 @@ class MemoryLocal : public Memory { class MemoryRange : public Memory { public: - MemoryRange(Memory* memory, uint64_t begin, uint64_t end); - virtual ~MemoryRange() { delete memory_; } + MemoryRange(const std::shared_ptr<Memory>& memory, uint64_t begin, uint64_t end); + virtual ~MemoryRange() = default; bool Read(uint64_t addr, void* dst, size_t size) override; private: - Memory* memory_; + std::shared_ptr<Memory> memory_; uint64_t begin_; uint64_t length_; }; diff --git a/libunwindstack/tests/MapInfoCreateMemoryTest.cpp b/libunwindstack/tests/MapInfoCreateMemoryTest.cpp index 2aab9c652..d2aad49fa 100644 --- a/libunwindstack/tests/MapInfoCreateMemoryTest.cpp +++ b/libunwindstack/tests/MapInfoCreateMemoryTest.cpp @@ -34,6 +34,8 @@ #include <unwindstack/MapInfo.h> #include <unwindstack/Memory.h> +#include "MemoryFake.h" + namespace unwindstack { class MapInfoCreateMemoryTest : public ::testing::Test { @@ -71,6 +73,14 @@ class MapInfoCreateMemoryTest : public ::testing::Test { InitElf<Elf64_Ehdr, Elf64_Shdr>(elf64_at_map_.fd, 0x2000, 0x3000, ELFCLASS64); } + void SetUp() override { + memory_ = new MemoryFake; + process_memory_.reset(memory_); + } + + MemoryFake* memory_; + std::shared_ptr<Memory> process_memory_; + static TemporaryFile elf_; static TemporaryFile elf_at_100_; @@ -86,17 +96,16 @@ TemporaryFile MapInfoCreateMemoryTest::elf64_at_map_; TEST_F(MapInfoCreateMemoryTest, end_le_start) { MapInfo info{.start = 0x100, .end = 0x100, .offset = 0, .name = elf_.path}; - std::unique_ptr<Memory> memory; - memory.reset(info.CreateMemory(getpid())); + std::unique_ptr<Memory> memory(info.CreateMemory(process_memory_)); ASSERT_TRUE(memory.get() == nullptr); info.end = 0xff; - memory.reset(info.CreateMemory(getpid())); + memory.reset(info.CreateMemory(process_memory_)); ASSERT_TRUE(memory.get() == nullptr); // Make sure this test is valid. info.end = 0x101; - memory.reset(info.CreateMemory(getpid())); + memory.reset(info.CreateMemory(process_memory_)); ASSERT_TRUE(memory.get() != nullptr); } @@ -105,7 +114,7 @@ TEST_F(MapInfoCreateMemoryTest, end_le_start) { 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())); + std::unique_ptr<Memory> memory(info.CreateMemory(process_memory_)); ASSERT_TRUE(memory.get() != nullptr); ASSERT_EQ(0x100U, info.elf_offset); @@ -126,7 +135,7 @@ TEST_F(MapInfoCreateMemoryTest, file_backed_non_zero_offset_full_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())); + std::unique_ptr<Memory> memory(info.CreateMemory(process_memory_)); ASSERT_TRUE(memory.get() != nullptr); ASSERT_EQ(0U, info.elf_offset); @@ -149,7 +158,7 @@ TEST_F(MapInfoCreateMemoryTest, file_backed_non_zero_offset_partial_file) { 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())); + std::unique_ptr<Memory> memory(info.CreateMemory(process_memory_)); ASSERT_TRUE(memory.get() != nullptr); ASSERT_EQ(0U, info.elf_offset); @@ -165,7 +174,7 @@ TEST_F(MapInfoCreateMemoryTest, file_backed_non_zero_offset_partial_file_whole_e 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())); + std::unique_ptr<Memory> memory(info.CreateMemory(process_memory_)); ASSERT_TRUE(memory.get() != nullptr); ASSERT_EQ(0U, info.elf_offset); @@ -187,81 +196,38 @@ TEST_F(MapInfoCreateMemoryTest, check_device_maps) { info.start = reinterpret_cast<uint64_t>(buffer.data()); info.end = info.start + buffer.size(); info.offset = 0; - std::unique_ptr<Memory> memory; info.flags = 0x8000; info.name = "/dev/something"; - memory.reset(info.CreateMemory(getpid())); + std::unique_ptr<Memory> memory(info.CreateMemory(process_memory_)); ASSERT_TRUE(memory.get() == nullptr); } -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++) { - buffer[i] = i % 256; - } - +TEST_F(MapInfoCreateMemoryTest, process_memory) { MapInfo info; - info.start = reinterpret_cast<uint64_t>(buffer.data()); - info.end = info.start + buffer.size(); + info.start = 0x2000; + info.end = 0x3000; info.offset = 0; - std::unique_ptr<Memory> memory; - memory.reset(info.CreateMemory(getpid())); - ASSERT_TRUE(memory.get() != nullptr); - - std::vector<uint8_t> read_buffer(1024); - ASSERT_TRUE(memory->Read(0, read_buffer.data(), read_buffer.size())); - for (size_t i = 0; i < read_buffer.size(); i++) { - ASSERT_EQ(i % 256, read_buffer[i]) << "Failed at byte " << i; - } - - ASSERT_FALSE(memory->Read(read_buffer.size(), read_buffer.data(), 1)); -} - -TEST_F(MapInfoCreateMemoryTest, remote_memory) { + // Verify that the the process_memory object is used, so seed it + // with memory. std::vector<uint8_t> buffer(1024); - memset(buffer.data(), 0xa, buffer.size()); - - pid_t pid; - if ((pid = fork()) == 0) { - while (true) - ; - exit(1); - } - ASSERT_LT(0, pid); - - ASSERT_TRUE(ptrace(PTRACE_ATTACH, pid, 0, 0) != -1); - uint64_t iterations = 0; - siginfo_t si; - while (TEMP_FAILURE_RETRY(ptrace(PTRACE_GETSIGINFO, pid, 0, &si)) < 0 && errno == ESRCH) { - usleep(30); - iterations++; - ASSERT_LT(iterations, 500000000ULL); + for (size_t i = 0; i < buffer.size(); i++) { + buffer[i] = i % 256; } + memory_->SetMemory(info.start, buffer.data(), buffer.size()); - MapInfo info; - info.start = reinterpret_cast<uint64_t>(buffer.data()); - info.end = info.start + buffer.size(); - info.offset = 0; - - std::unique_ptr<Memory> memory; - memory.reset(info.CreateMemory(pid)); + std::unique_ptr<Memory> memory(info.CreateMemory(process_memory_)); ASSERT_TRUE(memory.get() != nullptr); - // Set the local memory to a different value to guarantee we are reading - // from the remote process. - memset(buffer.data(), 0x1, buffer.size()); - std::vector<uint8_t> read_buffer(1024); - ASSERT_TRUE(memory->Read(0, read_buffer.data(), read_buffer.size())); - for (size_t i = 0; i < read_buffer.size(); i++) { - ASSERT_EQ(0xaU, read_buffer[i]) << "Failed at byte " << i; - } - ASSERT_TRUE(ptrace(PTRACE_DETACH, pid, 0, 0) == 0); + memset(buffer.data(), 0, buffer.size()); + ASSERT_TRUE(memory->Read(0, buffer.data(), buffer.size())); + for (size_t i = 0; i < buffer.size(); i++) { + ASSERT_EQ(i % 256, buffer[i]) << "Failed at byte " << i; + } - kill(pid, SIGKILL); - ASSERT_EQ(pid, wait(nullptr)); + // Try to read outside of the map size. + ASSERT_FALSE(memory->Read(buffer.size(), buffer.data(), 1)); } } // namespace unwindstack diff --git a/libunwindstack/tests/MapInfoGetElfTest.cpp b/libunwindstack/tests/MapInfoGetElfTest.cpp index abfa172aa..0b70d1337 100644 --- a/libunwindstack/tests/MapInfoGetElfTest.cpp +++ b/libunwindstack/tests/MapInfoGetElfTest.cpp @@ -32,43 +32,57 @@ #include <unwindstack/Elf.h> #include <unwindstack/MapInfo.h> +#include <unwindstack/Maps.h> #include <unwindstack/Memory.h> #include "ElfTestUtils.h" +#include "MemoryFake.h" namespace unwindstack { 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 = ""}); + memory_ = new MemoryFake; + process_memory_.reset(memory_); } - void TearDown() override { munmap(map_, kMapSize); } + template <typename Ehdr, typename Shdr> + static void InitElf(uint64_t sh_offset, Ehdr* ehdr, uint8_t class_type, uint8_t machine_type) { + memset(ehdr, 0, sizeof(*ehdr)); + memcpy(ehdr->e_ident, ELFMAG, SELFMAG); + ehdr->e_ident[EI_CLASS] = class_type; + ehdr->e_machine = machine_type; + ehdr->e_shoff = sh_offset; + ehdr->e_shentsize = sizeof(Shdr) + 100; + ehdr->e_shnum = 4; + } const size_t kMapSize = 4096; - void* map_ = nullptr; - std::unique_ptr<MapInfo> info_; + std::shared_ptr<Memory> process_memory_; + MemoryFake* memory_; + + TemporaryFile elf_; }; TEST_F(MapInfoGetElfTest, invalid) { + MapInfo info{.start = 0x1000, .end = 0x2000, .offset = 0, .flags = PROT_READ, .name = ""}; + // The map is empty, but this should still create an invalid elf object. - std::unique_ptr<Elf> elf(info_->GetElf(getpid(), false)); + std::unique_ptr<Elf> elf(info.GetElf(process_memory_, false)); ASSERT_TRUE(elf.get() != nullptr); ASSERT_FALSE(elf->valid()); } TEST_F(MapInfoGetElfTest, valid32) { + MapInfo info{.start = 0x3000, .end = 0x4000, .offset = 0, .flags = PROT_READ, .name = ""}; + Elf32_Ehdr ehdr; TestInitEhdr<Elf32_Ehdr>(&ehdr, ELFCLASS32, EM_ARM); - memcpy(map_, &ehdr, sizeof(ehdr)); + memory_->SetMemory(0x3000, &ehdr, sizeof(ehdr)); - std::unique_ptr<Elf> elf(info_->GetElf(getpid(), false)); + std::unique_ptr<Elf> elf(info.GetElf(process_memory_, false)); ASSERT_TRUE(elf.get() != nullptr); ASSERT_TRUE(elf->valid()); EXPECT_EQ(static_cast<uint32_t>(EM_ARM), elf->machine_type()); @@ -76,11 +90,13 @@ TEST_F(MapInfoGetElfTest, valid32) { } TEST_F(MapInfoGetElfTest, valid64) { + MapInfo info{.start = 0x8000, .end = 0x9000, .offset = 0, .flags = PROT_READ, .name = ""}; + Elf64_Ehdr ehdr; TestInitEhdr<Elf64_Ehdr>(&ehdr, ELFCLASS64, EM_AARCH64); - memcpy(map_, &ehdr, sizeof(ehdr)); + memory_->SetMemory(0x8000, &ehdr, sizeof(ehdr)); - std::unique_ptr<Elf> elf(info_->GetElf(getpid(), false)); + std::unique_ptr<Elf> elf(info.GetElf(process_memory_, false)); ASSERT_TRUE(elf.get() != nullptr); ASSERT_TRUE(elf->valid()); EXPECT_EQ(static_cast<uint32_t>(EM_AARCH64), elf->machine_type()); @@ -88,12 +104,14 @@ TEST_F(MapInfoGetElfTest, valid64) { } 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); - }); + MapInfo info{.start = 0x4000, .end = 0x8000, .offset = 0, .flags = PROT_READ, .name = ""}; + + TestInitGnuDebugdata<Elf32_Ehdr, Elf32_Shdr>(ELFCLASS32, EM_ARM, false, + [&](uint64_t offset, const void* ptr, size_t size) { + memory_->SetMemory(0x4000 + offset, ptr, size); + }); - std::unique_ptr<Elf> elf(info_->GetElf(getpid(), false)); + std::unique_ptr<Elf> elf(info.GetElf(process_memory_, false)); ASSERT_TRUE(elf.get() != nullptr); ASSERT_TRUE(elf->valid()); EXPECT_EQ(static_cast<uint32_t>(EM_ARM), elf->machine_type()); @@ -102,12 +120,14 @@ TEST_F(MapInfoGetElfTest, gnu_debugdata_do_not_init32) { } 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); - }); + MapInfo info{.start = 0x6000, .end = 0x8000, .offset = 0, .flags = PROT_READ, .name = ""}; + + TestInitGnuDebugdata<Elf64_Ehdr, Elf64_Shdr>(ELFCLASS64, EM_AARCH64, false, + [&](uint64_t offset, const void* ptr, size_t size) { + memory_->SetMemory(0x6000 + offset, ptr, size); + }); - std::unique_ptr<Elf> elf(info_->GetElf(getpid(), false)); + std::unique_ptr<Elf> elf(info.GetElf(process_memory_, false)); ASSERT_TRUE(elf.get() != nullptr); ASSERT_TRUE(elf->valid()); EXPECT_EQ(static_cast<uint32_t>(EM_AARCH64), elf->machine_type()); @@ -116,12 +136,14 @@ TEST_F(MapInfoGetElfTest, gnu_debugdata_do_not_init64) { } 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); - }); + MapInfo info{.start = 0x2000, .end = 0x3000, .offset = 0, .flags = PROT_READ, .name = ""}; - std::unique_ptr<Elf> elf(info_->GetElf(getpid(), true)); + TestInitGnuDebugdata<Elf32_Ehdr, Elf32_Shdr>(ELFCLASS32, EM_ARM, true, + [&](uint64_t offset, const void* ptr, size_t size) { + memory_->SetMemory(0x2000 + offset, ptr, size); + }); + + std::unique_ptr<Elf> elf(info.GetElf(process_memory_, true)); ASSERT_TRUE(elf.get() != nullptr); ASSERT_TRUE(elf->valid()); EXPECT_EQ(static_cast<uint32_t>(EM_ARM), elf->machine_type()); @@ -130,12 +152,14 @@ TEST_F(MapInfoGetElfTest, gnu_debugdata_init32) { } 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); - }); + MapInfo info{.start = 0x5000, .end = 0x8000, .offset = 0, .flags = PROT_READ, .name = ""}; + + TestInitGnuDebugdata<Elf64_Ehdr, Elf64_Shdr>(ELFCLASS64, EM_AARCH64, true, + [&](uint64_t offset, const void* ptr, size_t size) { + memory_->SetMemory(0x5000 + offset, ptr, size); + }); - std::unique_ptr<Elf> elf(info_->GetElf(getpid(), true)); + std::unique_ptr<Elf> elf(info.GetElf(process_memory_, true)); ASSERT_TRUE(elf.get() != nullptr); ASSERT_TRUE(elf->valid()); EXPECT_EQ(static_cast<uint32_t>(EM_AARCH64), elf->machine_type()); @@ -143,4 +167,195 @@ TEST_F(MapInfoGetElfTest, gnu_debugdata_init64) { EXPECT_TRUE(elf->gnu_debugdata_interface() != nullptr); } +TEST_F(MapInfoGetElfTest, end_le_start) { + MapInfo info{.start = 0x1000, .end = 0x1000, .offset = 0, .flags = PROT_READ, .name = elf_.path}; + + Elf32_Ehdr ehdr; + TestInitEhdr<Elf32_Ehdr>(&ehdr, ELFCLASS32, EM_ARM); + ASSERT_TRUE(android::base::WriteFully(elf_.fd, &ehdr, sizeof(ehdr))); + + std::unique_ptr<Elf> elf(info.GetElf(process_memory_, false)); + ASSERT_FALSE(elf->valid()); + + info.elf = nullptr; + info.end = 0xfff; + elf.reset(info.GetElf(process_memory_, false)); + ASSERT_FALSE(elf->valid()); + + // Make sure this test is valid. + info.elf = nullptr; + info.end = 0x2000; + elf.reset(info.GetElf(process_memory_, false)); + ASSERT_TRUE(elf->valid()); +} + +// Verify that if the offset is non-zero but there is no elf at the offset, +// that the full file is used. +TEST_F(MapInfoGetElfTest, file_backed_non_zero_offset_full_file) { + MapInfo info{ + .start = 0x1000, .end = 0x2000, .offset = 0x100, .flags = PROT_READ, .name = elf_.path}; + + std::vector<uint8_t> buffer(0x1000); + memset(buffer.data(), 0, buffer.size()); + Elf32_Ehdr ehdr; + TestInitEhdr<Elf32_Ehdr>(&ehdr, ELFCLASS32, EM_ARM); + memcpy(buffer.data(), &ehdr, sizeof(ehdr)); + ASSERT_TRUE(android::base::WriteFully(elf_.fd, buffer.data(), buffer.size())); + + std::unique_ptr<Elf> elf(info.GetElf(process_memory_, false)); + ASSERT_TRUE(elf->valid()); + ASSERT_TRUE(elf->memory() != nullptr); + ASSERT_EQ(0x100U, info.elf_offset); + + // Read the entire file. + memset(buffer.data(), 0, buffer.size()); + ASSERT_TRUE(elf->memory()->Read(0, buffer.data(), buffer.size())); + ASSERT_EQ(0, memcmp(buffer.data(), &ehdr, sizeof(ehdr))); + for (size_t i = sizeof(ehdr); i < buffer.size(); i++) { + ASSERT_EQ(0, buffer[i]) << "Failed at byte " << i; + } + + ASSERT_FALSE(elf->memory()->Read(buffer.size(), 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. +TEST_F(MapInfoGetElfTest, file_backed_non_zero_offset_partial_file) { + MapInfo info{ + .start = 0x1000, .end = 0x2000, .offset = 0x2000, .flags = PROT_READ, .name = elf_.path}; + + std::vector<uint8_t> buffer(0x4000); + memset(buffer.data(), 0, buffer.size()); + Elf32_Ehdr ehdr; + TestInitEhdr<Elf32_Ehdr>(&ehdr, ELFCLASS32, EM_ARM); + memcpy(&buffer[info.offset], &ehdr, sizeof(ehdr)); + ASSERT_TRUE(android::base::WriteFully(elf_.fd, buffer.data(), buffer.size())); + + std::unique_ptr<Elf> elf(info.GetElf(process_memory_, false)); + ASSERT_TRUE(elf->valid()); + ASSERT_TRUE(elf->memory() != nullptr); + ASSERT_EQ(0U, info.elf_offset); + + // Read the valid part of the file. + ASSERT_TRUE(elf->memory()->Read(0, buffer.data(), 0x1000)); + ASSERT_EQ(0, memcmp(buffer.data(), &ehdr, sizeof(ehdr))); + for (size_t i = sizeof(ehdr); i < 0x1000; i++) { + ASSERT_EQ(0, buffer[i]) << "Failed at byte " << i; + } + + ASSERT_FALSE(elf->memory()->Read(0x1000, 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(MapInfoGetElfTest, file_backed_non_zero_offset_partial_file_whole_elf32) { + MapInfo info{ + .start = 0x5000, .end = 0x6000, .offset = 0x1000, .flags = PROT_READ, .name = elf_.path}; + + std::vector<uint8_t> buffer(0x4000); + memset(buffer.data(), 0, buffer.size()); + Elf32_Ehdr ehdr; + TestInitEhdr<Elf32_Ehdr>(&ehdr, ELFCLASS32, EM_ARM); + ehdr.e_shoff = 0x2000; + ehdr.e_shentsize = sizeof(Elf32_Shdr) + 100; + ehdr.e_shnum = 4; + memcpy(&buffer[info.offset], &ehdr, sizeof(ehdr)); + ASSERT_TRUE(android::base::WriteFully(elf_.fd, buffer.data(), buffer.size())); + + std::unique_ptr<Elf> elf(info.GetElf(process_memory_, false)); + ASSERT_TRUE(elf->valid()); + ASSERT_TRUE(elf->memory() != nullptr); + ASSERT_EQ(0U, info.elf_offset); + + // Verify the memory is a valid elf. + memset(buffer.data(), 0, buffer.size()); + ASSERT_TRUE(elf->memory()->Read(0, buffer.data(), 0x1000)); + ASSERT_EQ(0, memcmp(buffer.data(), &ehdr, sizeof(ehdr))); + + // Read past the end of what would normally be the size of the map. + ASSERT_TRUE(elf->memory()->Read(0x1000, buffer.data(), 1)); +} + +TEST_F(MapInfoGetElfTest, file_backed_non_zero_offset_partial_file_whole_elf64) { + MapInfo info{ + .start = 0x7000, .end = 0x8000, .offset = 0x1000, .flags = PROT_READ, .name = elf_.path}; + + std::vector<uint8_t> buffer(0x4000); + memset(buffer.data(), 0, buffer.size()); + Elf64_Ehdr ehdr; + TestInitEhdr<Elf64_Ehdr>(&ehdr, ELFCLASS64, EM_AARCH64); + ehdr.e_shoff = 0x2000; + ehdr.e_shentsize = sizeof(Elf64_Shdr) + 100; + ehdr.e_shnum = 4; + memcpy(&buffer[info.offset], &ehdr, sizeof(ehdr)); + ASSERT_TRUE(android::base::WriteFully(elf_.fd, buffer.data(), buffer.size())); + + std::unique_ptr<Elf> elf(info.GetElf(process_memory_, false)); + ASSERT_TRUE(elf->valid()); + ASSERT_TRUE(elf->memory() != nullptr); + ASSERT_EQ(0U, info.elf_offset); + + // Verify the memory is a valid elf. + memset(buffer.data(), 0, buffer.size()); + ASSERT_TRUE(elf->memory()->Read(0, buffer.data(), 0x1000)); + ASSERT_EQ(0, memcmp(buffer.data(), &ehdr, sizeof(ehdr))); + + // Read past the end of what would normally be the size of the map. + ASSERT_TRUE(elf->memory()->Read(0x1000, buffer.data(), 1)); +} + +TEST_F(MapInfoGetElfTest, process_memory_not_read_only) { + MapInfo info{.start = 0x9000, .end = 0xa000, .offset = 0x1000, .flags = 0, .name = ""}; + + // Create valid elf data in process memory only. + Elf64_Ehdr ehdr; + TestInitEhdr<Elf64_Ehdr>(&ehdr, ELFCLASS64, EM_AARCH64); + ehdr.e_shoff = 0x2000; + ehdr.e_shentsize = sizeof(Elf64_Shdr) + 100; + ehdr.e_shnum = 4; + memory_->SetMemory(0x9000, &ehdr, sizeof(ehdr)); + + std::unique_ptr<Elf> elf(info.GetElf(process_memory_, false)); + ASSERT_FALSE(elf->valid()); + + info.elf = nullptr; + info.flags = PROT_READ; + elf.reset(info.GetElf(process_memory_, false)); + ASSERT_TRUE(elf->valid()); +} + +TEST_F(MapInfoGetElfTest, check_device_maps) { + MapInfo info{.start = 0x7000, + .end = 0x8000, + .offset = 0x1000, + .flags = PROT_READ | MAPS_FLAGS_DEVICE_MAP, + .name = "/dev/something"}; + + // Create valid elf data in process memory for this to verify that only + // the name is causing invalid elf data. + Elf64_Ehdr ehdr; + TestInitEhdr<Elf64_Ehdr>(&ehdr, ELFCLASS64, EM_X86_64); + ehdr.e_shoff = 0x2000; + ehdr.e_shentsize = sizeof(Elf64_Shdr) + 100; + ehdr.e_shnum = 4; + memory_->SetMemory(0x7000, &ehdr, sizeof(ehdr)); + + std::unique_ptr<Elf> elf(info.GetElf(process_memory_, false)); + ASSERT_FALSE(elf->valid()); + + // Set the name to nothing to verify that it still fails. + info.elf = nullptr; + info.name = ""; + elf.reset(info.GetElf(process_memory_, false)); + ASSERT_FALSE(elf->valid()); + + // Change the flags and verify the elf is valid now. + info.elf = nullptr; + info.flags = PROT_READ; + elf.reset(info.GetElf(process_memory_, false)); + ASSERT_TRUE(elf->valid()); +} + } // namespace unwindstack diff --git a/libunwindstack/tests/MemoryRangeTest.cpp b/libunwindstack/tests/MemoryRangeTest.cpp index 6d1366c84..680fae9c1 100644 --- a/libunwindstack/tests/MemoryRangeTest.cpp +++ b/libunwindstack/tests/MemoryRangeTest.cpp @@ -31,10 +31,11 @@ namespace unwindstack { TEST(MemoryRangeTest, read) { std::vector<uint8_t> src(1024); memset(src.data(), 0x4c, 1024); - MemoryFake* memory = new MemoryFake; - memory->SetMemory(9001, src); + MemoryFake* memory_fake = new MemoryFake; + std::shared_ptr<Memory> process_memory(memory_fake); + memory_fake->SetMemory(9001, src); - MemoryRange range(memory, 9001, 9001 + src.size()); + MemoryRange range(process_memory, 9001, 9001 + src.size()); std::vector<uint8_t> dst(1024); ASSERT_TRUE(range.Read(0, dst.data(), src.size())); @@ -46,10 +47,11 @@ TEST(MemoryRangeTest, read) { TEST(MemoryRangeTest, read_near_limit) { std::vector<uint8_t> src(4096); memset(src.data(), 0x4c, 4096); - MemoryFake* memory = new MemoryFake; - memory->SetMemory(1000, src); + MemoryFake* memory_fake = new MemoryFake; + std::shared_ptr<Memory> process_memory(memory_fake); + memory_fake->SetMemory(1000, src); - MemoryRange range(memory, 1000, 2024); + MemoryRange range(process_memory, 1000, 2024); std::vector<uint8_t> dst(1024); ASSERT_TRUE(range.Read(1020, dst.data(), 4)); @@ -69,7 +71,8 @@ TEST(MemoryRangeTest, read_near_limit) { TEST(MemoryRangeTest, read_overflow) { std::vector<uint8_t> buffer(100); - std::unique_ptr<MemoryRange> overflow(new MemoryRange(new MemoryFakeAlwaysReadZero, 100, 200)); + std::shared_ptr<Memory> process_memory(new MemoryFakeAlwaysReadZero); + std::unique_ptr<MemoryRange> overflow(new MemoryRange(process_memory, 100, 200)); ASSERT_FALSE(overflow->Read(UINT64_MAX - 10, buffer.data(), 100)); } diff --git a/libunwindstack/tests/UnwindTest.cpp b/libunwindstack/tests/UnwindTest.cpp index 2fc3a3880..a0c45bdf3 100644 --- a/libunwindstack/tests/UnwindTest.cpp +++ b/libunwindstack/tests/UnwindTest.cpp @@ -85,10 +85,11 @@ static std::string ErrorMsg(const std::vector<const char*>& function_names, size function_names[index] + "\n" + "Unwind data:\n" + unwind_stream.str(); } -static void VerifyUnwind(pid_t pid, Memory* memory, Maps* maps, Regs* regs, +static void VerifyUnwind(pid_t pid, Maps* maps, Regs* regs, std::vector<const char*>& function_names) { size_t function_name_index = 0; + auto process_memory = Memory::CreateProcessMemory(pid); std::stringstream unwind_stream; unwind_stream << std::hex; for (size_t frame_num = 0; frame_num < 64; frame_num++) { @@ -96,7 +97,7 @@ static void VerifyUnwind(pid_t pid, Memory* memory, Maps* maps, Regs* regs, MapInfo* map_info = maps->Find(regs->pc()); ASSERT_TRUE(map_info != nullptr) << ErrorMsg(function_names, function_name_index, unwind_stream); - Elf* elf = map_info->GetElf(pid, true); + Elf* elf = map_info->GetElf(process_memory, true); uint64_t rel_pc = elf->GetRelPc(regs->pc(), map_info); uint64_t adjusted_rel_pc = rel_pc; if (frame_num != 0) { @@ -122,7 +123,7 @@ static void VerifyUnwind(pid_t pid, Memory* memory, Maps* maps, Regs* regs, unwind_stream << " " << name; } unwind_stream << "\n"; - ASSERT_TRUE(elf->Step(rel_pc + map_info->elf_offset, regs, memory)) + ASSERT_TRUE(elf->Step(rel_pc + map_info->elf_offset, regs, process_memory.get())) << ErrorMsg(function_names, function_name_index, unwind_stream); } ASSERT_TRUE(false) << ErrorMsg(function_names, function_name_index, unwind_stream); @@ -137,9 +138,8 @@ extern "C" void InnerFunction(bool local) { ASSERT_TRUE(maps.Parse()); std::unique_ptr<Regs> regs(Regs::CreateFromLocal()); RegsGetLocal(regs.get()); - MemoryLocal memory; - VerifyUnwind(getpid(), &memory, &maps, regs.get(), kFunctionOrder); + VerifyUnwind(getpid(), &maps, regs.get(), kFunctionOrder); } else { g_ready_for_remote = true; g_ready = true; @@ -205,11 +205,10 @@ TEST(UnwindTest, remote) { RemoteMaps maps(pid); ASSERT_TRUE(maps.Parse()); - MemoryRemote memory(pid); std::unique_ptr<Regs> regs(Regs::RemoteGet(pid)); ASSERT_TRUE(regs.get() != nullptr); - VerifyUnwind(pid, &memory, &maps, regs.get(), kFunctionOrder); + VerifyUnwind(pid, &maps, regs.get(), kFunctionOrder); ASSERT_EQ(0, ptrace(PTRACE_DETACH, pid, 0, 0)); @@ -254,9 +253,8 @@ TEST(UnwindTest, from_context) { LocalMaps maps; ASSERT_TRUE(maps.Parse()); std::unique_ptr<Regs> regs(Regs::CreateFromUcontext(Regs::CurrentMachineType(), ucontext)); - MemoryLocal memory; - VerifyUnwind(tid.load(), &memory, &maps, regs.get(), kFunctionOrder); + VerifyUnwind(getpid(), &maps, regs.get(), kFunctionOrder); ASSERT_EQ(0, sigaction(SIGUSR1, &oldact, nullptr)); @@ -291,11 +289,10 @@ static void RemoteThroughSignal(unsigned int sa_flags) { RemoteMaps maps(pid); ASSERT_TRUE(maps.Parse()); - MemoryRemote memory(pid); std::unique_ptr<Regs> regs(Regs::RemoteGet(pid)); ASSERT_TRUE(regs.get() != nullptr); - VerifyUnwind(pid, &memory, &maps, regs.get(), kFunctionSignalOrder); + VerifyUnwind(pid, &maps, regs.get(), kFunctionSignalOrder); ASSERT_EQ(0, ptrace(PTRACE_DETACH, pid, 0, 0)); diff --git a/libunwindstack/tools/unwind.cpp b/libunwindstack/tools/unwind.cpp index c1077f8b6..3614198eb 100644 --- a/libunwindstack/tools/unwind.cpp +++ b/libunwindstack/tools/unwind.cpp @@ -91,7 +91,7 @@ void DoUnwind(pid_t pid) { } printf("\n"); - unwindstack::MemoryRemote remote_memory(pid); + auto process_memory = unwindstack::Memory::CreateProcessMemory(pid); for (size_t frame_num = 0; frame_num < 64; frame_num++) { if (regs->pc() == 0) { break; @@ -102,7 +102,7 @@ void DoUnwind(pid_t pid) { break; } - unwindstack::Elf* elf = map_info->GetElf(pid, true); + unwindstack::Elf* elf = map_info->GetElf(process_memory, true); uint64_t rel_pc = elf->GetRelPc(regs->pc(), map_info); uint64_t adjusted_rel_pc = rel_pc; @@ -135,7 +135,7 @@ void DoUnwind(pid_t pid) { } printf("\n"); - if (!elf->Step(rel_pc + map_info->elf_offset, regs, &remote_memory)) { + if (!elf->Step(rel_pc + map_info->elf_offset, regs, process_memory.get())) { break; } } |