diff --git a/libbacktrace/Android.bp b/libbacktrace/Android.bp index 43bcd9823..7f9a18a3d 100644 --- a/libbacktrace/Android.bp +++ b/libbacktrace/Android.bp @@ -116,10 +116,6 @@ cc_test_library { target: { linux_glibc: { - // The host uses rosegment, which isn't supported yet. - ldflags: [ - "-Wl,--no-rosegment", - ], // This forces the creation of eh_frame with unwind information // for host. cflags: [ diff --git a/libunwindstack/Android.bp b/libunwindstack/Android.bp index be2145d03..970e05c42 100644 --- a/libunwindstack/Android.bp +++ b/libunwindstack/Android.bp @@ -178,6 +178,7 @@ cc_test { "tests/JitDebugTest.cpp", "tests/LocalUnwinderTest.cpp", "tests/LogFake.cpp", + "tests/MapInfoCreateMemoryTest.cpp", "tests/MapInfoGetElfTest.cpp", "tests/MapInfoGetLoadBiasTest.cpp", "tests/MapsTest.cpp", @@ -188,6 +189,7 @@ cc_test { "tests/MemoryOfflineBufferTest.cpp", "tests/MemoryOfflineTest.cpp", "tests/MemoryRangeTest.cpp", + "tests/MemoryRangesTest.cpp", "tests/MemoryRemoteTest.cpp", "tests/MemoryTest.cpp", "tests/RegsInfoTest.cpp", diff --git a/libunwindstack/MapInfo.cpp b/libunwindstack/MapInfo.cpp index 39378a3af..64005ae12 100644 --- a/libunwindstack/MapInfo.cpp +++ b/libunwindstack/MapInfo.cpp @@ -102,7 +102,54 @@ Memory* MapInfo::CreateMemory(const std::shared_ptr& process_memory) { if (!(flags & PROT_READ)) { return nullptr; } - return new MemoryRange(process_memory, start, end - start, 0); + + // Need to verify that this elf is valid. It's possible that + // only part of the elf file to be mapped into memory is in the executable + // map. In this case, there will be another read-only map that includes the + // first part of the elf file. This is done if the linker rosegment + // option is used. + std::unique_ptr memory(new MemoryRange(process_memory, start, end - start, 0)); + bool valid; + uint64_t max_size; + Elf::GetInfo(memory.get(), &valid, &max_size); + if (valid) { + // Valid elf, we are done. + return memory.release(); + } + + if (name.empty() || maps_ == nullptr) { + return nullptr; + } + + // Find the read-only map that has the same name and has an offset closest + // to the current offset but less than the offset of the current map. + // For shared libraries, there should be a r-x map that has a non-zero + // offset and then a r-- map that has a zero offset. + // For shared libraries loaded from an apk, there should be a r-x map that + // has a non-zero offset and then a r-- map that has a non-zero offset less + // than the offset from the r-x map. + uint64_t closest_offset = 0; + MapInfo* ro_map_info = nullptr; + for (auto map_info : *maps_) { + if (map_info->flags == PROT_READ && map_info->name == name && map_info->offset < offset && + map_info->offset >= closest_offset) { + ro_map_info = map_info; + closest_offset = ro_map_info->offset; + } + } + + if (ro_map_info != nullptr) { + // Make sure that relative pc values are corrected properly. + elf_offset = offset - closest_offset; + + MemoryRanges* ranges = new MemoryRanges; + ranges->Insert(new MemoryRange(process_memory, ro_map_info->start, + ro_map_info->end - ro_map_info->start, 0)); + ranges->Insert(new MemoryRange(process_memory, start, end - start, elf_offset)); + + return ranges; + } + return nullptr; } Elf* MapInfo::GetElf(const std::shared_ptr& process_memory, bool init_gnu_debugdata) { diff --git a/libunwindstack/Maps.cpp b/libunwindstack/Maps.cpp index e676a5a97..87298719e 100644 --- a/libunwindstack/Maps.cpp +++ b/libunwindstack/Maps.cpp @@ -66,13 +66,13 @@ bool Maps::Parse() { if (strncmp(name, "/dev/", 5) == 0 && strncmp(name + 5, "ashmem/", 7) != 0) { flags |= unwindstack::MAPS_FLAGS_DEVICE_MAP; } - maps_.push_back(new MapInfo(start, end, pgoff, flags, name)); + maps_.push_back(new MapInfo(this, start, end, pgoff, flags, name)); }); } void Maps::Add(uint64_t start, uint64_t end, uint64_t offset, uint64_t flags, const std::string& name, uint64_t load_bias) { - MapInfo* map_info = new MapInfo(start, end, offset, flags, name); + MapInfo* map_info = new MapInfo(this, start, end, offset, flags, name); map_info->load_bias = load_bias; maps_.push_back(map_info); } @@ -97,7 +97,7 @@ bool BufferMaps::Parse() { if (strncmp(name, "/dev/", 5) == 0 && strncmp(name + 5, "ashmem/", 7) != 0) { flags |= unwindstack::MAPS_FLAGS_DEVICE_MAP; } - maps_.push_back(new MapInfo(start, end, pgoff, flags, name)); + maps_.push_back(new MapInfo(this, start, end, pgoff, flags, name)); }); } diff --git a/libunwindstack/Memory.cpp b/libunwindstack/Memory.cpp index beb2aade8..cfa8c6d93 100644 --- a/libunwindstack/Memory.cpp +++ b/libunwindstack/Memory.cpp @@ -316,6 +316,18 @@ size_t MemoryRange::Read(uint64_t addr, void* dst, size_t size) { return memory_->Read(read_addr, dst, read_length); } +void MemoryRanges::Insert(MemoryRange* memory) { + maps_.emplace(memory->offset() + memory->length(), memory); +} + +size_t MemoryRanges::Read(uint64_t addr, void* dst, size_t size) { + auto entry = maps_.upper_bound(addr); + if (entry != maps_.end()) { + return entry->second->Read(addr, dst, size); + } + return 0; +} + bool MemoryOffline::Init(const std::string& file, uint64_t offset) { auto memory_file = std::make_shared(); if (!memory_file->Init(file, offset)) { diff --git a/libunwindstack/include/unwindstack/MapInfo.h b/libunwindstack/include/unwindstack/MapInfo.h index ac0df41a4..9755c48b1 100644 --- a/libunwindstack/include/unwindstack/MapInfo.h +++ b/libunwindstack/include/unwindstack/MapInfo.h @@ -29,20 +29,25 @@ namespace unwindstack { // Forward declarations. +class Maps; class Memory; struct MapInfo { - MapInfo() = default; - MapInfo(uint64_t start, uint64_t end) : start(start), end(end) {} - MapInfo(uint64_t start, uint64_t end, uint64_t offset, uint64_t flags, const char* name) - : start(start), + MapInfo(Maps* maps) : maps_(maps) {} + MapInfo(Maps* maps, uint64_t start, uint64_t end) : maps_(maps), start(start), end(end) {} + MapInfo(Maps* maps, uint64_t start, uint64_t end, uint64_t offset, uint64_t flags, + const char* name) + : maps_(maps), + start(start), end(end), offset(offset), flags(flags), name(name), load_bias(static_cast(-1)) {} - MapInfo(uint64_t start, uint64_t end, uint64_t offset, uint64_t flags, const std::string& name) - : start(start), + MapInfo(Maps* maps, uint64_t start, uint64_t end, uint64_t offset, uint64_t flags, + const std::string& name) + : maps_(maps), + start(start), end(end), offset(offset), flags(flags), @@ -50,6 +55,8 @@ struct MapInfo { load_bias(static_cast(-1)) {} ~MapInfo() = default; + Maps* maps_ = nullptr; + uint64_t start = 0; uint64_t end = 0; uint64_t offset = 0; @@ -69,14 +76,14 @@ struct MapInfo { uint64_t GetLoadBias(const std::shared_ptr& process_memory); + Memory* CreateMemory(const std::shared_ptr& process_memory); + private: MapInfo(const MapInfo&) = delete; void operator=(const MapInfo&) = delete; Memory* GetFileMemory(); - Memory* CreateMemory(const std::shared_ptr& process_memory); - // Protect the creation of the elf object. std::mutex mutex_; }; diff --git a/libunwindstack/include/unwindstack/Memory.h b/libunwindstack/include/unwindstack/Memory.h index dee5e983c..9c425cb73 100644 --- a/libunwindstack/include/unwindstack/Memory.h +++ b/libunwindstack/include/unwindstack/Memory.h @@ -22,6 +22,7 @@ #include #include +#include #include #include #include @@ -119,6 +120,9 @@ class MemoryRange : public Memory { size_t Read(uint64_t addr, void* dst, size_t size) override; + uint64_t offset() { return offset_; } + uint64_t length() { return length_; } + private: std::shared_ptr memory_; uint64_t begin_; @@ -126,6 +130,19 @@ class MemoryRange : public Memory { uint64_t offset_; }; +class MemoryRanges : public Memory { + public: + MemoryRanges() = default; + virtual ~MemoryRanges() = default; + + void Insert(MemoryRange* memory); + + size_t Read(uint64_t addr, void* dst, size_t size) override; + + private: + std::map> maps_; +}; + class MemoryOffline : public Memory { public: MemoryOffline() = default; diff --git a/libunwindstack/tests/DexFileTest.cpp b/libunwindstack/tests/DexFileTest.cpp index 4dd8cb046..40f9f8ea9 100644 --- a/libunwindstack/tests/DexFileTest.cpp +++ b/libunwindstack/tests/DexFileTest.cpp @@ -120,7 +120,7 @@ TEST(DexFileTest, create_using_file) { static_cast(TEMP_FAILURE_RETRY(write(tf.fd, kDexData, sizeof(kDexData))))); MemoryFake memory; - MapInfo info(0, 0x10000, 0, 0x5, tf.path); + MapInfo info(nullptr, 0, 0x10000, 0, 0x5, tf.path); std::unique_ptr dex_file(DexFile::Create(0x500, &memory, &info)); ASSERT_TRUE(dex_file != nullptr); } @@ -134,7 +134,7 @@ TEST(DexFileTest, create_using_file_non_zero_start) { static_cast(TEMP_FAILURE_RETRY(write(tf.fd, kDexData, sizeof(kDexData))))); MemoryFake memory; - MapInfo info(0x100, 0x10000, 0, 0x5, tf.path); + MapInfo info(nullptr, 0x100, 0x10000, 0, 0x5, tf.path); std::unique_ptr dex_file(DexFile::Create(0x600, &memory, &info)); ASSERT_TRUE(dex_file != nullptr); } @@ -148,7 +148,7 @@ TEST(DexFileTest, create_using_file_non_zero_offset) { static_cast(TEMP_FAILURE_RETRY(write(tf.fd, kDexData, sizeof(kDexData))))); MemoryFake memory; - MapInfo info(0x100, 0x10000, 0x200, 0x5, tf.path); + MapInfo info(nullptr, 0x100, 0x10000, 0x200, 0x5, tf.path); std::unique_ptr dex_file(DexFile::Create(0x400, &memory, &info)); ASSERT_TRUE(dex_file != nullptr); } @@ -156,7 +156,7 @@ TEST(DexFileTest, create_using_file_non_zero_offset) { TEST(DexFileTest, create_using_memory_empty_file) { MemoryFake memory; memory.SetMemory(0x4000, kDexData, sizeof(kDexData)); - MapInfo info(0x100, 0x10000, 0x200, 0x5, ""); + MapInfo info(nullptr, 0x100, 0x10000, 0x200, 0x5, ""); std::unique_ptr dex_file(DexFile::Create(0x4000, &memory, &info)); ASSERT_TRUE(dex_file != nullptr); } @@ -164,7 +164,7 @@ TEST(DexFileTest, create_using_memory_empty_file) { TEST(DexFileTest, create_using_memory_file_does_not_exist) { MemoryFake memory; memory.SetMemory(0x4000, kDexData, sizeof(kDexData)); - MapInfo info(0x100, 0x10000, 0x200, 0x5, "/does/not/exist"); + MapInfo info(nullptr, 0x100, 0x10000, 0x200, 0x5, "/does/not/exist"); std::unique_ptr dex_file(DexFile::Create(0x4000, &memory, &info)); ASSERT_TRUE(dex_file != nullptr); } @@ -178,7 +178,7 @@ TEST(DexFileTest, create_using_memory_file_is_malformed) { MemoryFake memory; memory.SetMemory(0x4000, kDexData, sizeof(kDexData)); - MapInfo info(0x4000, 0x10000, 0x200, 0x5, "/does/not/exist"); + MapInfo info(nullptr, 0x4000, 0x10000, 0x200, 0x5, "/does/not/exist"); std::unique_ptr dex_file(DexFile::Create(0x4000, &memory, &info)); ASSERT_TRUE(dex_file != nullptr); @@ -200,7 +200,7 @@ TEST(DexFileTest, get_method_not_opened) { TEST(DexFileTest, get_method) { MemoryFake memory; memory.SetMemory(0x4000, kDexData, sizeof(kDexData)); - MapInfo info(0x100, 0x10000, 0x200, 0x5, ""); + MapInfo info(nullptr, 0x100, 0x10000, 0x200, 0x5, ""); std::unique_ptr dex_file(DexFile::Create(0x4000, &memory, &info)); ASSERT_TRUE(dex_file != nullptr); @@ -227,7 +227,7 @@ TEST(DexFileTest, get_method) { TEST(DexFileTest, get_method_empty) { MemoryFake memory; memory.SetMemory(0x4000, kDexData, sizeof(kDexData)); - MapInfo info(0x100, 0x10000, 0x200, 0x5, ""); + MapInfo info(nullptr, 0x100, 0x10000, 0x200, 0x5, ""); std::unique_ptr dex_file(DexFile::Create(0x4000, &memory, &info)); ASSERT_TRUE(dex_file != nullptr); diff --git a/libunwindstack/tests/ElfCacheTest.cpp b/libunwindstack/tests/ElfCacheTest.cpp index 89331ea26..1afd4efaf 100644 --- a/libunwindstack/tests/ElfCacheTest.cpp +++ b/libunwindstack/tests/ElfCacheTest.cpp @@ -79,8 +79,8 @@ void ElfCacheTest::VerifySameMap(bool cache_enabled) { uint64_t start = 0x1000; uint64_t end = 0x20000; - MapInfo info1(start, end, 0, 0x5, tf.path); - MapInfo info2(start, end, 0, 0x5, tf.path); + MapInfo info1(nullptr, start, end, 0, 0x5, tf.path); + MapInfo info2(nullptr, start, end, 0, 0x5, tf.path); Elf* elf1 = info1.GetElf(memory_, true); ASSERT_TRUE(elf1->valid()); @@ -120,17 +120,17 @@ void ElfCacheTest::VerifyWithinSameMap(bool cache_enabled) { uint64_t start = 0x1000; uint64_t end = 0x20000; // Will have an elf at offset 0 in file. - MapInfo info0_1(start, end, 0, 0x5, tf.path); - MapInfo info0_2(start, end, 0, 0x5, tf.path); + MapInfo info0_1(nullptr, start, end, 0, 0x5, tf.path); + MapInfo info0_2(nullptr, start, end, 0, 0x5, tf.path); // Will have an elf at offset 0x100 in file. - MapInfo info100_1(start, end, 0x100, 0x5, tf.path); - MapInfo info100_2(start, end, 0x100, 0x5, tf.path); + MapInfo info100_1(nullptr, start, end, 0x100, 0x5, tf.path); + MapInfo info100_2(nullptr, start, end, 0x100, 0x5, tf.path); // Will have an elf at offset 0x200 in file. - MapInfo info200_1(start, end, 0x200, 0x5, tf.path); - MapInfo info200_2(start, end, 0x200, 0x5, tf.path); + MapInfo info200_1(nullptr, start, end, 0x200, 0x5, tf.path); + MapInfo info200_2(nullptr, start, end, 0x200, 0x5, tf.path); // Will have an elf at offset 0 in file. - MapInfo info300_1(start, end, 0x300, 0x5, tf.path); - MapInfo info300_2(start, end, 0x300, 0x5, tf.path); + MapInfo info300_1(nullptr, start, end, 0x300, 0x5, tf.path); + MapInfo info300_2(nullptr, start, end, 0x300, 0x5, tf.path); Elf* elf0_1 = info0_1.GetElf(memory_, true); ASSERT_TRUE(elf0_1->valid()); @@ -217,10 +217,10 @@ void ElfCacheTest::VerifyWithinSameMapNeverReadAtZero(bool cache_enabled) { uint64_t start = 0x1000; uint64_t end = 0x20000; // Multiple info sections at different offsets will have non-zero elf offsets. - MapInfo info300_1(start, end, 0x300, 0x5, tf.path); - MapInfo info300_2(start, end, 0x300, 0x5, tf.path); - MapInfo info400_1(start, end, 0x400, 0x5, tf.path); - MapInfo info400_2(start, end, 0x400, 0x5, tf.path); + MapInfo info300_1(nullptr, start, end, 0x300, 0x5, tf.path); + MapInfo info300_2(nullptr, start, end, 0x300, 0x5, tf.path); + MapInfo info400_1(nullptr, start, end, 0x400, 0x5, tf.path); + MapInfo info400_2(nullptr, start, end, 0x400, 0x5, tf.path); Elf* elf300_1 = info300_1.GetElf(memory_, true); ASSERT_TRUE(elf300_1->valid()); diff --git a/libunwindstack/tests/ElfTest.cpp b/libunwindstack/tests/ElfTest.cpp index 55fe16f14..9a117b2f8 100644 --- a/libunwindstack/tests/ElfTest.cpp +++ b/libunwindstack/tests/ElfTest.cpp @@ -297,7 +297,7 @@ TEST_F(ElfTest, rel_pc) { elf.FakeSetInterface(interface); elf.FakeSetValid(true); - MapInfo map_info(0x1000, 0x2000); + MapInfo map_info(nullptr, 0x1000, 0x2000); ASSERT_EQ(0x101U, elf.GetRelPc(0x1101, &map_info)); diff --git a/libunwindstack/tests/MapInfoCreateMemoryTest.cpp b/libunwindstack/tests/MapInfoCreateMemoryTest.cpp index 866b5b4ef..2a73c7efb 100644 --- a/libunwindstack/tests/MapInfoCreateMemoryTest.cpp +++ b/libunwindstack/tests/MapInfoCreateMemoryTest.cpp @@ -32,8 +32,10 @@ #include #include +#include #include +#include "ElfTestUtils.h" #include "MemoryFake.h" namespace unwindstack { @@ -94,7 +96,7 @@ TemporaryFile MapInfoCreateMemoryTest::elf32_at_map_; TemporaryFile MapInfoCreateMemoryTest::elf64_at_map_; TEST_F(MapInfoCreateMemoryTest, end_le_start) { - MapInfo info(0x100, 0x100, 0, 0, elf_.path); + MapInfo info(nullptr, 0x100, 0x100, 0, 0, elf_.path); std::unique_ptr memory(info.CreateMemory(process_memory_)); ASSERT_TRUE(memory.get() == nullptr); @@ -112,7 +114,7 @@ TEST_F(MapInfoCreateMemoryTest, 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(MapInfoCreateMemoryTest, file_backed_non_zero_offset_full_file) { - MapInfo info(0x100, 0x200, 0x100, 0, elf_.path); + MapInfo info(nullptr, 0x100, 0x200, 0x100, 0, elf_.path); std::unique_ptr memory(info.CreateMemory(process_memory_)); ASSERT_TRUE(memory.get() != nullptr); @@ -133,7 +135,7 @@ TEST_F(MapInfoCreateMemoryTest, 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(MapInfoCreateMemoryTest, file_backed_non_zero_offset_partial_file) { - MapInfo info(0x100, 0x200, 0x100, 0, elf_at_100_.path); + MapInfo info(nullptr, 0x100, 0x200, 0x100, 0, elf_at_100_.path); std::unique_ptr memory(info.CreateMemory(process_memory_)); ASSERT_TRUE(memory.get() != nullptr); @@ -156,7 +158,7 @@ TEST_F(MapInfoCreateMemoryTest, file_backed_non_zero_offset_partial_file) { // 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(0x5000, 0x6000, 0x1000, 0, elf32_at_map_.path); + MapInfo info(nullptr, 0x5000, 0x6000, 0x1000, 0, elf32_at_map_.path); std::unique_ptr memory(info.CreateMemory(process_memory_)); ASSERT_TRUE(memory.get() != nullptr); @@ -172,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(0x7000, 0x8000, 0x2000, 0, elf64_at_map_.path); + MapInfo info(nullptr, 0x7000, 0x8000, 0x2000, 0, elf64_at_map_.path); std::unique_ptr memory(info.CreateMemory(process_memory_)); ASSERT_TRUE(memory.get() != nullptr); @@ -192,27 +194,24 @@ 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 buffer(1024); - MapInfo info; - info.start = reinterpret_cast(buffer.data()); - info.end = info.start + buffer.size(); - info.offset = 0; + uint64_t start = reinterpret_cast(buffer.data()); + MapInfo info(nullptr, start, start + buffer.size(), 0, 0x8000, "/dev/something"); - info.flags = 0x8000; - info.name = "/dev/something"; std::unique_ptr memory(info.CreateMemory(process_memory_)); ASSERT_TRUE(memory.get() == nullptr); } TEST_F(MapInfoCreateMemoryTest, process_memory) { - MapInfo info; - info.start = 0x2000; - info.end = 0x3000; - info.offset = 0; + MapInfo info(nullptr, 0x2000, 0x3000, 0, PROT_READ, ""); + + Elf32_Ehdr ehdr = {}; + TestInitEhdr(&ehdr, ELFCLASS32, EM_ARM); + std::vector buffer(1024); + memcpy(buffer.data(), &ehdr, sizeof(ehdr)); // Verify that the the process_memory object is used, so seed it // with memory. - std::vector buffer(1024); - for (size_t i = 0; i < buffer.size(); i++) { + for (size_t i = sizeof(ehdr); i < buffer.size(); i++) { buffer[i] = i % 256; } memory_->SetMemory(info.start, buffer.data(), buffer.size()); @@ -222,7 +221,8 @@ TEST_F(MapInfoCreateMemoryTest, process_memory) { memset(buffer.data(), 0, buffer.size()); ASSERT_TRUE(memory->ReadFully(0, buffer.data(), buffer.size())); - for (size_t i = 0; i < buffer.size(); i++) { + ASSERT_EQ(0, memcmp(&ehdr, buffer.data(), sizeof(ehdr))); + for (size_t i = sizeof(ehdr); i < buffer.size(); i++) { ASSERT_EQ(i % 256, buffer[i]) << "Failed at byte " << i; } @@ -230,4 +230,87 @@ TEST_F(MapInfoCreateMemoryTest, process_memory) { ASSERT_FALSE(memory->ReadFully(buffer.size(), buffer.data(), 1)); } +TEST_F(MapInfoCreateMemoryTest, valid_rosegment_zero_offset) { + Maps maps; + maps.Add(0x500, 0x600, 0, PROT_READ, "something_else", 0); + maps.Add(0x1000, 0x2600, 0, PROT_READ, "/only/in/memory.so", 0); + maps.Add(0x3000, 0x5000, 0x4000, PROT_READ | PROT_EXEC, "/only/in/memory.so", 0); + + Elf32_Ehdr ehdr = {}; + TestInitEhdr(&ehdr, ELFCLASS32, EM_ARM); + memory_->SetMemory(0x1000, &ehdr, sizeof(ehdr)); + memory_->SetMemoryBlock(0x1000 + sizeof(ehdr), 0x1600 - sizeof(ehdr), 0xab); + + // Set the memory in the r-x map. + memory_->SetMemoryBlock(0x3000, 0x2000, 0x5d); + + MapInfo* map_info = maps.Find(0x3000); + ASSERT_TRUE(map_info != nullptr); + + std::unique_ptr mem(map_info->CreateMemory(process_memory_)); + ASSERT_TRUE(mem.get() != nullptr); + EXPECT_EQ(0x4000UL, map_info->elf_offset); + EXPECT_EQ(0x4000UL, map_info->offset); + + // Verify that reading values from this memory works properly. + std::vector buffer(0x4000); + size_t bytes = mem->Read(0, buffer.data(), buffer.size()); + ASSERT_EQ(0x1600UL, bytes); + ASSERT_EQ(0, memcmp(&ehdr, buffer.data(), sizeof(ehdr))); + for (size_t i = sizeof(ehdr); i < bytes; i++) { + ASSERT_EQ(0xab, buffer[i]) << "Failed at byte " << i; + } + + bytes = mem->Read(0x4000, buffer.data(), buffer.size()); + ASSERT_EQ(0x2000UL, bytes); + for (size_t i = 0; i < bytes; i++) { + ASSERT_EQ(0x5d, buffer[i]) << "Failed at byte " << i; + } +} + +TEST_F(MapInfoCreateMemoryTest, valid_rosegment_non_zero_offset) { + Maps maps; + maps.Add(0x500, 0x600, 0, PROT_READ, "something_else", 0); + maps.Add(0x1000, 0x2000, 0, PROT_READ, "/only/in/memory.apk", 0); + maps.Add(0x2000, 0x3000, 0x1000, PROT_READ | PROT_EXEC, "/only/in/memory.apk", 0); + maps.Add(0x3000, 0x4000, 0xa000, PROT_READ, "/only/in/memory.apk", 0); + maps.Add(0x4000, 0x5000, 0xb000, PROT_READ | PROT_EXEC, "/only/in/memory.apk", 0); + + Elf32_Ehdr ehdr = {}; + TestInitEhdr(&ehdr, ELFCLASS32, EM_ARM); + + // Setup an elf at offset 0x1000 in memory. + memory_->SetMemory(0x1000, &ehdr, sizeof(ehdr)); + memory_->SetMemoryBlock(0x1000 + sizeof(ehdr), 0x2000 - sizeof(ehdr), 0x12); + memory_->SetMemoryBlock(0x2000, 0x1000, 0x23); + + // Setup an elf at offset 0x3000 in memory.. + memory_->SetMemory(0x3000, &ehdr, sizeof(ehdr)); + memory_->SetMemoryBlock(0x3000 + sizeof(ehdr), 0x4000 - sizeof(ehdr), 0x34); + memory_->SetMemoryBlock(0x4000, 0x1000, 0x43); + + MapInfo* map_info = maps.Find(0x4000); + ASSERT_TRUE(map_info != nullptr); + + std::unique_ptr mem(map_info->CreateMemory(process_memory_)); + ASSERT_TRUE(mem.get() != nullptr); + EXPECT_EQ(0x1000UL, map_info->elf_offset); + EXPECT_EQ(0xb000UL, map_info->offset); + + // Verify that reading values from this memory works properly. + std::vector buffer(0x4000); + size_t bytes = mem->Read(0, buffer.data(), buffer.size()); + ASSERT_EQ(0x1000UL, bytes); + ASSERT_EQ(0, memcmp(&ehdr, buffer.data(), sizeof(ehdr))); + for (size_t i = sizeof(ehdr); i < bytes; i++) { + ASSERT_EQ(0x34, buffer[i]) << "Failed at byte " << i; + } + + bytes = mem->Read(0x1000, buffer.data(), buffer.size()); + ASSERT_EQ(0x1000UL, bytes); + for (size_t i = 0; i < bytes; i++) { + ASSERT_EQ(0x43, buffer[i]) << "Failed at byte " << i; + } +} + } // namespace unwindstack diff --git a/libunwindstack/tests/MapInfoGetElfTest.cpp b/libunwindstack/tests/MapInfoGetElfTest.cpp index 861b82f07..918c028c7 100644 --- a/libunwindstack/tests/MapInfoGetElfTest.cpp +++ b/libunwindstack/tests/MapInfoGetElfTest.cpp @@ -69,7 +69,7 @@ class MapInfoGetElfTest : public ::testing::Test { }; TEST_F(MapInfoGetElfTest, invalid) { - MapInfo info(0x1000, 0x2000, 0, PROT_READ, ""); + MapInfo info(nullptr, 0x1000, 0x2000, 0, PROT_READ, ""); // The map is empty, but this should still create an invalid elf object. Elf* elf = info.GetElf(process_memory_, false); @@ -78,7 +78,7 @@ TEST_F(MapInfoGetElfTest, invalid) { } TEST_F(MapInfoGetElfTest, valid32) { - MapInfo info(0x3000, 0x4000, 0, PROT_READ, ""); + MapInfo info(nullptr, 0x3000, 0x4000, 0, PROT_READ, ""); Elf32_Ehdr ehdr; TestInitEhdr(&ehdr, ELFCLASS32, EM_ARM); @@ -92,7 +92,7 @@ TEST_F(MapInfoGetElfTest, valid32) { } TEST_F(MapInfoGetElfTest, valid64) { - MapInfo info(0x8000, 0x9000, 0, PROT_READ, ""); + MapInfo info(nullptr, 0x8000, 0x9000, 0, PROT_READ, ""); Elf64_Ehdr ehdr; TestInitEhdr(&ehdr, ELFCLASS64, EM_AARCH64); @@ -106,7 +106,7 @@ TEST_F(MapInfoGetElfTest, valid64) { } TEST_F(MapInfoGetElfTest, gnu_debugdata_do_not_init32) { - MapInfo info(0x4000, 0x8000, 0, PROT_READ, ""); + MapInfo info(nullptr, 0x4000, 0x8000, 0, PROT_READ, ""); TestInitGnuDebugdata(ELFCLASS32, EM_ARM, false, [&](uint64_t offset, const void* ptr, size_t size) { @@ -122,7 +122,7 @@ TEST_F(MapInfoGetElfTest, gnu_debugdata_do_not_init32) { } TEST_F(MapInfoGetElfTest, gnu_debugdata_do_not_init64) { - MapInfo info(0x6000, 0x8000, 0, PROT_READ, ""); + MapInfo info(nullptr, 0x6000, 0x8000, 0, PROT_READ, ""); TestInitGnuDebugdata(ELFCLASS64, EM_AARCH64, false, [&](uint64_t offset, const void* ptr, size_t size) { @@ -138,7 +138,7 @@ TEST_F(MapInfoGetElfTest, gnu_debugdata_do_not_init64) { } TEST_F(MapInfoGetElfTest, gnu_debugdata_init32) { - MapInfo info(0x2000, 0x3000, 0, PROT_READ, ""); + MapInfo info(nullptr, 0x2000, 0x3000, 0, PROT_READ, ""); TestInitGnuDebugdata(ELFCLASS32, EM_ARM, true, [&](uint64_t offset, const void* ptr, size_t size) { @@ -154,7 +154,7 @@ TEST_F(MapInfoGetElfTest, gnu_debugdata_init32) { } TEST_F(MapInfoGetElfTest, gnu_debugdata_init64) { - MapInfo info(0x5000, 0x8000, 0, PROT_READ, ""); + MapInfo info(nullptr, 0x5000, 0x8000, 0, PROT_READ, ""); TestInitGnuDebugdata(ELFCLASS64, EM_AARCH64, true, [&](uint64_t offset, const void* ptr, size_t size) { @@ -170,7 +170,7 @@ TEST_F(MapInfoGetElfTest, gnu_debugdata_init64) { } TEST_F(MapInfoGetElfTest, end_le_start) { - MapInfo info(0x1000, 0x1000, 0, PROT_READ, elf_.path); + MapInfo info(nullptr, 0x1000, 0x1000, 0, PROT_READ, elf_.path); Elf32_Ehdr ehdr; TestInitEhdr(&ehdr, ELFCLASS32, EM_ARM); @@ -197,7 +197,7 @@ TEST_F(MapInfoGetElfTest, 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(MapInfoGetElfTest, file_backed_non_zero_offset_full_file) { - MapInfo info(0x1000, 0x2000, 0x100, PROT_READ, elf_.path); + MapInfo info(nullptr, 0x1000, 0x2000, 0x100, PROT_READ, elf_.path); std::vector buffer(0x1000); memset(buffer.data(), 0, buffer.size()); @@ -226,7 +226,7 @@ TEST_F(MapInfoGetElfTest, 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(MapInfoGetElfTest, file_backed_non_zero_offset_partial_file) { - MapInfo info(0x1000, 0x2000, 0x2000, PROT_READ, elf_.path); + MapInfo info(nullptr, 0x1000, 0x2000, 0x2000, PROT_READ, elf_.path); std::vector buffer(0x4000); memset(buffer.data(), 0, buffer.size()); @@ -256,7 +256,7 @@ TEST_F(MapInfoGetElfTest, file_backed_non_zero_offset_partial_file) { // 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(0x5000, 0x6000, 0x1000, PROT_READ, elf_.path); + MapInfo info(nullptr, 0x5000, 0x6000, 0x1000, PROT_READ, elf_.path); std::vector buffer(0x4000); memset(buffer.data(), 0, buffer.size()); @@ -284,7 +284,7 @@ TEST_F(MapInfoGetElfTest, file_backed_non_zero_offset_partial_file_whole_elf32) } TEST_F(MapInfoGetElfTest, file_backed_non_zero_offset_partial_file_whole_elf64) { - MapInfo info(0x7000, 0x8000, 0x1000, PROT_READ, elf_.path); + MapInfo info(nullptr, 0x7000, 0x8000, 0x1000, PROT_READ, elf_.path); std::vector buffer(0x4000); memset(buffer.data(), 0, buffer.size()); @@ -312,7 +312,7 @@ TEST_F(MapInfoGetElfTest, file_backed_non_zero_offset_partial_file_whole_elf64) } TEST_F(MapInfoGetElfTest, process_memory_not_read_only) { - MapInfo info(0x9000, 0xa000, 0x1000, 0, ""); + MapInfo info(nullptr, 0x9000, 0xa000, 0x1000, 0, ""); // Create valid elf data in process memory only. Elf64_Ehdr ehdr; @@ -333,7 +333,8 @@ TEST_F(MapInfoGetElfTest, process_memory_not_read_only) { } TEST_F(MapInfoGetElfTest, check_device_maps) { - MapInfo info(0x7000, 0x8000, 0x1000, PROT_READ | MAPS_FLAGS_DEVICE_MAP, "/dev/something"); + MapInfo info(nullptr, 0x7000, 0x8000, 0x1000, PROT_READ | MAPS_FLAGS_DEVICE_MAP, + "/dev/something"); // Create valid elf data in process memory for this to verify that only // the name is causing invalid elf data. @@ -378,7 +379,7 @@ TEST_F(MapInfoGetElfTest, multiple_thread_get_elf) { wait = true; // Create all of the threads and have them do the GetElf at the same time // to make it likely that a race will occur. - MapInfo info(0x7000, 0x8000, 0x1000, PROT_READ, ""); + MapInfo info(nullptr, 0x7000, 0x8000, 0x1000, PROT_READ, ""); for (size_t i = 0; i < kNumConcurrentThreads; i++) { std::thread* thread = new std::thread([i, this, &wait, &info, &elf_in_threads]() { while (wait) diff --git a/libunwindstack/tests/MapInfoGetLoadBiasTest.cpp b/libunwindstack/tests/MapInfoGetLoadBiasTest.cpp index 7e64a8a67..f5ac6cb44 100644 --- a/libunwindstack/tests/MapInfoGetLoadBiasTest.cpp +++ b/libunwindstack/tests/MapInfoGetLoadBiasTest.cpp @@ -50,7 +50,7 @@ class MapInfoGetLoadBiasTest : public ::testing::Test { process_memory_.reset(memory_); elf_ = new ElfFake(new MemoryFake); elf_container_.reset(elf_); - map_info_.reset(new MapInfo(0x1000, 0x20000, 0, PROT_READ | PROT_WRITE, "")); + map_info_.reset(new MapInfo(nullptr, 0x1000, 0x20000, 0, PROT_READ | PROT_WRITE, "")); } void MultipleThreadTest(uint64_t expected_load_bias); @@ -63,7 +63,7 @@ class MapInfoGetLoadBiasTest : public ::testing::Test { }; TEST_F(MapInfoGetLoadBiasTest, no_elf_and_no_valid_elf_in_memory) { - MapInfo info(0x1000, 0x2000, 0, PROT_READ, ""); + MapInfo info(nullptr, 0x1000, 0x2000, 0, PROT_READ, ""); EXPECT_EQ(0U, info.GetLoadBias(process_memory_)); } diff --git a/libunwindstack/tests/MapsTest.cpp b/libunwindstack/tests/MapsTest.cpp index 9622ba507..6bdd0b260 100644 --- a/libunwindstack/tests/MapsTest.cpp +++ b/libunwindstack/tests/MapsTest.cpp @@ -63,7 +63,7 @@ TEST(MapsTest, map_add) { } TEST(MapsTest, verify_parse_line) { - MapInfo info; + MapInfo info(nullptr); VerifyLine("01-02 rwxp 03 04:05 06\n", &info); EXPECT_EQ(1U, info.start); @@ -136,7 +136,7 @@ TEST(MapsTest, verify_parse_line) { } TEST(MapsTest, verify_large_values) { - MapInfo info; + MapInfo info(nullptr); #if defined(__LP64__) VerifyLine("fabcdef012345678-f12345678abcdef8 rwxp f0b0d0f010305070 00:00 0\n", &info); EXPECT_EQ(0xfabcdef012345678UL, info.start); diff --git a/libunwindstack/tests/MemoryFake.cpp b/libunwindstack/tests/MemoryFake.cpp index 60936cd03..5695dfcba 100644 --- a/libunwindstack/tests/MemoryFake.cpp +++ b/libunwindstack/tests/MemoryFake.cpp @@ -23,6 +23,17 @@ namespace unwindstack { +void MemoryFake::SetMemoryBlock(uint64_t addr, size_t length, uint8_t value) { + for (size_t i = 0; i < length; i++, addr++) { + auto entry = data_.find(addr); + if (entry != data_.end()) { + entry->second = value; + } else { + data_.insert({addr, value}); + } + } +} + void MemoryFake::SetMemory(uint64_t addr, const void* memory, size_t length) { const uint8_t* src = reinterpret_cast(memory); for (size_t i = 0; i < length; i++, addr++) { diff --git a/libunwindstack/tests/MemoryFake.h b/libunwindstack/tests/MemoryFake.h index 764a6c33f..20610a5e9 100644 --- a/libunwindstack/tests/MemoryFake.h +++ b/libunwindstack/tests/MemoryFake.h @@ -36,6 +36,8 @@ class MemoryFake : public Memory { void SetMemory(uint64_t addr, const void* memory, size_t length); + void SetMemoryBlock(uint64_t addr, size_t length, uint8_t value); + void SetData8(uint64_t addr, uint8_t value) { SetMemory(addr, &value, sizeof(value)); } diff --git a/libunwindstack/tests/MemoryRangeTest.cpp b/libunwindstack/tests/MemoryRangeTest.cpp index cb1a0c993..2bac95b61 100644 --- a/libunwindstack/tests/MemoryRangeTest.cpp +++ b/libunwindstack/tests/MemoryRangeTest.cpp @@ -15,7 +15,6 @@ */ #include -#include #include #include @@ -28,30 +27,34 @@ namespace unwindstack { -TEST(MemoryRangeTest, read) { - std::vector src(1024); - memset(src.data(), 0x4c, 1024); - MemoryFake* memory_fake = new MemoryFake; - std::shared_ptr process_memory(memory_fake); - memory_fake->SetMemory(9001, src); +class MemoryRangeTest : public ::testing::Test { + protected: + void SetUp() override { + process_memory_.reset(); + memory_fake_ = new MemoryFake; + process_memory_.reset(memory_fake_); + } - MemoryRange range(process_memory, 9001, src.size(), 0); + std::shared_ptr process_memory_; + MemoryFake* memory_fake_ = nullptr; +}; + +TEST_F(MemoryRangeTest, read_fully) { + memory_fake_->SetMemoryBlock(9000, 2048, 0x4c); + + MemoryRange range(process_memory_, 9001, 1024, 0); std::vector dst(1024); - ASSERT_TRUE(range.ReadFully(0, dst.data(), src.size())); - for (size_t i = 0; i < 1024; i++) { + ASSERT_TRUE(range.ReadFully(0, dst.data(), dst.size())); + for (size_t i = 0; i < dst.size(); i++) { ASSERT_EQ(0x4cU, dst[i]) << "Failed at byte " << i; } } -TEST(MemoryRangeTest, read_near_limit) { - std::vector src(4096); - memset(src.data(), 0x4c, 4096); - MemoryFake* memory_fake = new MemoryFake; - std::shared_ptr process_memory(memory_fake); - memory_fake->SetMemory(1000, src); +TEST_F(MemoryRangeTest, read_fully_near_limit) { + memory_fake_->SetMemoryBlock(0, 8192, 0x4c); - MemoryRange range(process_memory, 1000, 1024, 0); + MemoryRange range(process_memory_, 1000, 1024, 0); std::vector dst(1024); ASSERT_TRUE(range.ReadFully(1020, dst.data(), 4)); @@ -68,7 +71,7 @@ TEST(MemoryRangeTest, read_near_limit) { ASSERT_TRUE(range.ReadFully(1020, dst.data(), 4)); } -TEST(MemoryRangeTest, read_overflow) { +TEST_F(MemoryRangeTest, read_fully_overflow) { std::vector buffer(100); std::shared_ptr process_memory(new MemoryFakeAlwaysReadZero); @@ -76,19 +79,28 @@ TEST(MemoryRangeTest, read_overflow) { ASSERT_FALSE(overflow->ReadFully(UINT64_MAX - 10, buffer.data(), 100)); } -TEST(MemoryRangeTest, Read) { - std::vector src(4096); - memset(src.data(), 0x4c, 4096); - MemoryFake* memory_fake = new MemoryFake; - std::shared_ptr process_memory(memory_fake); - memory_fake->SetMemory(1000, src); +TEST_F(MemoryRangeTest, read) { + memory_fake_->SetMemoryBlock(0, 4096, 0x4c); + + MemoryRange range(process_memory_, 1000, 1024, 0); - MemoryRange range(process_memory, 1000, 1024, 0); std::vector dst(1024); - ASSERT_EQ(4U, range.Read(1020, dst.data(), 1024)); + ASSERT_EQ(4U, range.Read(1020, dst.data(), dst.size())); for (size_t i = 0; i < 4; i++) { ASSERT_EQ(0x4cU, dst[i]) << "Failed at byte " << i; } } +TEST_F(MemoryRangeTest, read_non_zero_offset) { + memory_fake_->SetMemoryBlock(1000, 1024, 0x12); + + MemoryRange range(process_memory_, 1000, 1024, 400); + + std::vector dst(1024); + ASSERT_EQ(1024U, range.Read(400, dst.data(), dst.size())); + for (size_t i = 0; i < dst.size(); i++) { + ASSERT_EQ(0x12U, dst[i]) << "Failed at byte " << i; + } +} + } // namespace unwindstack diff --git a/libunwindstack/tests/MemoryRangesTest.cpp b/libunwindstack/tests/MemoryRangesTest.cpp new file mode 100644 index 000000000..d24fcd23f --- /dev/null +++ b/libunwindstack/tests/MemoryRangesTest.cpp @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2018 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 + +#include + +#include + +#include + +#include "MemoryFake.h" + +namespace unwindstack { + +class MemoryRangesTest : public ::testing::Test { + protected: + void SetUp() override { + MemoryFake* memory = new MemoryFake; + process_memory_.reset(memory); + memory->SetMemoryBlock(1000, 5000, 0x15); + memory->SetMemoryBlock(6000, 12000, 0x26); + memory->SetMemoryBlock(14000, 20000, 0x37); + memory->SetMemoryBlock(20000, 22000, 0x48); + + ranges_.reset(new MemoryRanges); + ranges_->Insert(new MemoryRange(process_memory_, 15000, 100, 4000)); + ranges_->Insert(new MemoryRange(process_memory_, 10000, 2000, 2000)); + ranges_->Insert(new MemoryRange(process_memory_, 3000, 1000, 0)); + ranges_->Insert(new MemoryRange(process_memory_, 19000, 1000, 6000)); + ranges_->Insert(new MemoryRange(process_memory_, 20000, 1000, 7000)); + } + + std::shared_ptr process_memory_; + std::unique_ptr ranges_; +}; + +TEST_F(MemoryRangesTest, read) { + std::vector dst(2000); + size_t bytes = ranges_->Read(0, dst.data(), dst.size()); + ASSERT_EQ(1000UL, bytes); + for (size_t i = 0; i < bytes; i++) { + ASSERT_EQ(0x15U, dst[i]) << "Failed at byte " << i; + } + + bytes = ranges_->Read(2000, dst.data(), dst.size()); + ASSERT_EQ(2000UL, bytes); + for (size_t i = 0; i < bytes; i++) { + ASSERT_EQ(0x26U, dst[i]) << "Failed at byte " << i; + } + + bytes = ranges_->Read(4000, dst.data(), dst.size()); + ASSERT_EQ(100UL, bytes); + for (size_t i = 0; i < bytes; i++) { + ASSERT_EQ(0x37U, dst[i]) << "Failed at byte " << i; + } +} + +TEST_F(MemoryRangesTest, read_fail) { + std::vector dst(4096); + ASSERT_EQ(0UL, ranges_->Read(1000, dst.data(), dst.size())); + ASSERT_EQ(0UL, ranges_->Read(5000, dst.data(), dst.size())); + ASSERT_EQ(0UL, ranges_->Read(8000, dst.data(), dst.size())); +} + +TEST_F(MemoryRangesTest, read_across_ranges) { + // The MemoryRanges object does not support reading across a range, + // so this will only read in the first range. + std::vector dst(4096); + size_t bytes = ranges_->Read(6000, dst.data(), dst.size()); + ASSERT_EQ(1000UL, bytes); + for (size_t i = 0; i < bytes; i++) { + ASSERT_EQ(0x37U, dst[i]) << "Failed at byte " << i; + } +} + +} // namespace unwindstack diff --git a/libunwindstack/tests/RegsTest.cpp b/libunwindstack/tests/RegsTest.cpp index 90c3fe619..00264c2c5 100644 --- a/libunwindstack/tests/RegsTest.cpp +++ b/libunwindstack/tests/RegsTest.cpp @@ -182,7 +182,7 @@ TEST_F(RegsTest, elf_invalid) { RegsX86_64 regs_x86_64; RegsMips regs_mips; RegsMips64 regs_mips64; - MapInfo map_info(0x1000, 0x2000); + MapInfo map_info(nullptr, 0x1000, 0x2000); Elf* invalid_elf = new Elf(nullptr); map_info.elf.reset(invalid_elf); diff --git a/libunwindstack/tests/UnwinderTest.cpp b/libunwindstack/tests/UnwinderTest.cpp index 2428f68fd..436903022 100644 --- a/libunwindstack/tests/UnwinderTest.cpp +++ b/libunwindstack/tests/UnwinderTest.cpp @@ -58,51 +58,54 @@ class UnwinderTest : public ::testing::Test { protected: static void SetUpTestCase() { maps_.FakeClear(); - MapInfo* info = new MapInfo(0x1000, 0x8000, 0, PROT_READ | PROT_WRITE, "/system/fake/libc.so"); + MapInfo* info = + new MapInfo(&maps_, 0x1000, 0x8000, 0, PROT_READ | PROT_WRITE, "/system/fake/libc.so"); ElfFake* elf = new ElfFake(new MemoryFake); info->elf.reset(elf); elf->FakeSetInterface(new ElfInterfaceFake(nullptr)); maps_.FakeAddMapInfo(info); - info = new MapInfo(0x10000, 0x12000, 0, PROT_READ | PROT_WRITE, "[stack]"); + info = new MapInfo(&maps_, 0x10000, 0x12000, 0, PROT_READ | PROT_WRITE, "[stack]"); maps_.FakeAddMapInfo(info); - info = new MapInfo(0x13000, 0x15000, 0, PROT_READ | PROT_WRITE | MAPS_FLAGS_DEVICE_MAP, + info = new MapInfo(&maps_, 0x13000, 0x15000, 0, PROT_READ | PROT_WRITE | MAPS_FLAGS_DEVICE_MAP, "/dev/fake_device"); maps_.FakeAddMapInfo(info); - info = new MapInfo(0x20000, 0x22000, 0, PROT_READ | PROT_WRITE, "/system/fake/libunwind.so"); + info = new MapInfo(&maps_, 0x20000, 0x22000, 0, PROT_READ | PROT_WRITE, + "/system/fake/libunwind.so"); elf = new ElfFake(new MemoryFake); info->elf.reset(elf); elf->FakeSetInterface(new ElfInterfaceFake(nullptr)); maps_.FakeAddMapInfo(info); - info = new MapInfo(0x23000, 0x24000, 0, PROT_READ | PROT_WRITE, "/fake/libanother.so"); + info = new MapInfo(&maps_, 0x23000, 0x24000, 0, PROT_READ | PROT_WRITE, "/fake/libanother.so"); elf = new ElfFake(new MemoryFake); info->elf.reset(elf); elf->FakeSetInterface(new ElfInterfaceFake(nullptr)); maps_.FakeAddMapInfo(info); - info = new MapInfo(0x33000, 0x34000, 0, PROT_READ | PROT_WRITE, "/fake/compressed.so"); + info = new MapInfo(&maps_, 0x33000, 0x34000, 0, PROT_READ | PROT_WRITE, "/fake/compressed.so"); elf = new ElfFake(new MemoryFake); info->elf.reset(elf); elf->FakeSetInterface(new ElfInterfaceFake(nullptr)); maps_.FakeAddMapInfo(info); - info = new MapInfo(0x43000, 0x44000, 0x1d000, PROT_READ | PROT_WRITE, "/fake/fake.apk"); + info = new MapInfo(&maps_, 0x43000, 0x44000, 0x1d000, PROT_READ | PROT_WRITE, "/fake/fake.apk"); elf = new ElfFake(new MemoryFake); info->elf.reset(elf); elf->FakeSetInterface(new ElfInterfaceFake(nullptr)); maps_.FakeAddMapInfo(info); - info = new MapInfo(0x53000, 0x54000, 0, PROT_READ | PROT_WRITE, "/fake/fake.oat"); + info = new MapInfo(&maps_, 0x53000, 0x54000, 0, PROT_READ | PROT_WRITE, "/fake/fake.oat"); maps_.FakeAddMapInfo(info); - info = new MapInfo(0xa3000, 0xa4000, 0, PROT_READ | PROT_WRITE | PROT_EXEC, "/fake/fake.vdex"); + info = new MapInfo(&maps_, 0xa3000, 0xa4000, 0, PROT_READ | PROT_WRITE | PROT_EXEC, + "/fake/fake.vdex"); info->load_bias = 0; maps_.FakeAddMapInfo(info); - info = new MapInfo(0xa5000, 0xa6000, 0, PROT_READ | PROT_WRITE | PROT_EXEC, + info = new MapInfo(&maps_, 0xa5000, 0xa6000, 0, PROT_READ | PROT_WRITE | PROT_EXEC, "/fake/fake_load_bias.so"); elf = new ElfFake(new MemoryFake); info->elf.reset(elf); @@ -110,7 +113,7 @@ class UnwinderTest : public ::testing::Test { elf->FakeSetLoadBias(0x5000); maps_.FakeAddMapInfo(info); - info = new MapInfo(0xa7000, 0xa8000, 0, PROT_READ | PROT_WRITE | PROT_EXEC, + info = new MapInfo(&maps_, 0xa7000, 0xa8000, 0, PROT_READ | PROT_WRITE | PROT_EXEC, "/fake/fake_offset.oat"); elf = new ElfFake(new MemoryFake); info->elf.reset(elf);