1 /*
2  * Copyright (C) 2016 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include <elf.h>
18 #include <errno.h>
19 #include <signal.h>
20 #include <string.h>
21 #include <sys/mman.h>
22 #include <sys/ptrace.h>
23 #include <sys/types.h>
24 #include <unistd.h>
25 
26 #include <atomic>
27 #include <memory>
28 #include <thread>
29 #include <vector>
30 
31 #include <android-base/file.h>
32 #include <gtest/gtest.h>
33 
34 #include <unwindstack/Elf.h>
35 #include <unwindstack/MapInfo.h>
36 #include <unwindstack/Maps.h>
37 #include <unwindstack/Memory.h>
38 
39 #include "ElfTestUtils.h"
40 #include "MemoryFake.h"
41 
42 namespace unwindstack {
43 
44 class MapInfoGetElfTest : public ::testing::Test {
45  protected:
SetUp()46   void SetUp() override {
47     memory_ = new MemoryFake;
48     process_memory_.reset(memory_);
49   }
50 
51   template <typename Ehdr, typename Shdr>
InitElf(uint64_t sh_offset,Ehdr * ehdr,uint8_t class_type,uint8_t machine_type)52   static void InitElf(uint64_t sh_offset, Ehdr* ehdr, uint8_t class_type, uint8_t machine_type) {
53     memset(ehdr, 0, sizeof(*ehdr));
54     memcpy(ehdr->e_ident, ELFMAG, SELFMAG);
55     ehdr->e_ident[EI_CLASS] = class_type;
56     ehdr->e_machine = machine_type;
57     ehdr->e_shoff = sh_offset;
58     ehdr->e_shentsize = sizeof(Shdr) + 100;
59     ehdr->e_shnum = 4;
60   }
61 
62   void InitMapInfo(std::vector<std::unique_ptr<MapInfo>>& maps, bool in_memory);
63 
64   const size_t kMapSize = 4096;
65 
66   std::shared_ptr<Memory> process_memory_;
67   MemoryFake* memory_;
68 
69   TemporaryFile elf_;
70 };
71 
TEST_F(MapInfoGetElfTest,invalid)72 TEST_F(MapInfoGetElfTest, invalid) {
73   MapInfo info(nullptr, nullptr, 0x1000, 0x2000, 0, PROT_READ, "");
74 
75   // The map is empty, but this should still create an invalid elf object.
76   Elf* elf = info.GetElf(process_memory_, ARCH_ARM);
77   ASSERT_TRUE(elf != nullptr);
78   ASSERT_FALSE(elf->valid());
79 }
80 
TEST_F(MapInfoGetElfTest,valid32)81 TEST_F(MapInfoGetElfTest, valid32) {
82   MapInfo info(nullptr, nullptr, 0x3000, 0x4000, 0, PROT_READ, "");
83 
84   Elf32_Ehdr ehdr;
85   TestInitEhdr<Elf32_Ehdr>(&ehdr, ELFCLASS32, EM_ARM);
86   memory_->SetMemory(0x3000, &ehdr, sizeof(ehdr));
87 
88   Elf* elf = info.GetElf(process_memory_, ARCH_ARM);
89   ASSERT_TRUE(elf != nullptr);
90   ASSERT_TRUE(elf->valid());
91   EXPECT_EQ(static_cast<uint32_t>(EM_ARM), elf->machine_type());
92   EXPECT_EQ(ELFCLASS32, elf->class_type());
93 
94   // Now verify that an empty process memory returns an invalid elf object.
95   info.set_elf(nullptr);
96   elf = info.GetElf(std::shared_ptr<Memory>(), ARCH_ARM);
97   ASSERT_TRUE(elf != nullptr);
98   ASSERT_FALSE(elf->valid());
99 }
100 
TEST_F(MapInfoGetElfTest,valid64)101 TEST_F(MapInfoGetElfTest, valid64) {
102   MapInfo info(nullptr, nullptr, 0x8000, 0x9000, 0, PROT_READ, "");
103 
104   Elf64_Ehdr ehdr;
105   TestInitEhdr<Elf64_Ehdr>(&ehdr, ELFCLASS64, EM_AARCH64);
106   memory_->SetMemory(0x8000, &ehdr, sizeof(ehdr));
107 
108   Elf* elf = info.GetElf(process_memory_, ARCH_ARM64);
109   ASSERT_TRUE(elf != nullptr);
110   ASSERT_TRUE(elf->valid());
111   EXPECT_EQ(static_cast<uint32_t>(EM_AARCH64), elf->machine_type());
112   EXPECT_EQ(ELFCLASS64, elf->class_type());
113 }
114 
TEST_F(MapInfoGetElfTest,invalid_arch_mismatch)115 TEST_F(MapInfoGetElfTest, invalid_arch_mismatch) {
116   MapInfo info(nullptr, nullptr, 0x3000, 0x4000, 0, PROT_READ, "");
117 
118   Elf32_Ehdr ehdr;
119   TestInitEhdr<Elf32_Ehdr>(&ehdr, ELFCLASS32, EM_ARM);
120   memory_->SetMemory(0x3000, &ehdr, sizeof(ehdr));
121 
122   Elf* elf = info.GetElf(process_memory_, ARCH_X86);
123   ASSERT_TRUE(elf != nullptr);
124   ASSERT_FALSE(elf->valid());
125 }
126 
TEST_F(MapInfoGetElfTest,gnu_debugdata_init32)127 TEST_F(MapInfoGetElfTest, gnu_debugdata_init32) {
128   MapInfo info(nullptr, nullptr, 0x2000, 0x3000, 0, PROT_READ, "");
129 
130   TestInitGnuDebugdata<Elf32_Ehdr, Elf32_Shdr>(ELFCLASS32, EM_ARM, true,
131                                                [&](uint64_t offset, const void* ptr, size_t size) {
132                                                  memory_->SetMemory(0x2000 + offset, ptr, size);
133                                                });
134 
135   Elf* elf = info.GetElf(process_memory_, ARCH_ARM);
136   ASSERT_TRUE(elf != nullptr);
137   ASSERT_TRUE(elf->valid());
138   EXPECT_EQ(static_cast<uint32_t>(EM_ARM), elf->machine_type());
139   EXPECT_EQ(ELFCLASS32, elf->class_type());
140   EXPECT_TRUE(elf->gnu_debugdata_interface() != nullptr);
141 }
142 
TEST_F(MapInfoGetElfTest,gnu_debugdata_init64)143 TEST_F(MapInfoGetElfTest, gnu_debugdata_init64) {
144   MapInfo info(nullptr, nullptr, 0x5000, 0x8000, 0, PROT_READ, "");
145 
146   TestInitGnuDebugdata<Elf64_Ehdr, Elf64_Shdr>(ELFCLASS64, EM_AARCH64, true,
147                                                [&](uint64_t offset, const void* ptr, size_t size) {
148                                                  memory_->SetMemory(0x5000 + offset, ptr, size);
149                                                });
150 
151   Elf* elf = info.GetElf(process_memory_, ARCH_ARM64);
152   ASSERT_TRUE(elf != nullptr);
153   ASSERT_TRUE(elf->valid());
154   EXPECT_EQ(static_cast<uint32_t>(EM_AARCH64), elf->machine_type());
155   EXPECT_EQ(ELFCLASS64, elf->class_type());
156   EXPECT_TRUE(elf->gnu_debugdata_interface() != nullptr);
157 }
158 
TEST_F(MapInfoGetElfTest,end_le_start)159 TEST_F(MapInfoGetElfTest, end_le_start) {
160   MapInfo info(nullptr, nullptr, 0x1000, 0x1000, 0, PROT_READ, elf_.path);
161 
162   Elf32_Ehdr ehdr;
163   TestInitEhdr<Elf32_Ehdr>(&ehdr, ELFCLASS32, EM_ARM);
164   ASSERT_TRUE(android::base::WriteFully(elf_.fd, &ehdr, sizeof(ehdr)));
165 
166   Elf* elf = info.GetElf(process_memory_, ARCH_ARM);
167   ASSERT_TRUE(elf != nullptr);
168   ASSERT_FALSE(elf->valid());
169 
170   info.set_elf(nullptr);
171   info.set_end(0xfff);
172   elf = info.GetElf(process_memory_, ARCH_ARM);
173   ASSERT_TRUE(elf != nullptr);
174   ASSERT_FALSE(elf->valid());
175 
176   // Make sure this test is valid.
177   info.set_elf(nullptr);
178   info.set_end(0x2000);
179   elf = info.GetElf(process_memory_, ARCH_ARM);
180   ASSERT_TRUE(elf != nullptr);
181   ASSERT_TRUE(elf->valid());
182 }
183 
184 // Verify that if the offset is non-zero but there is no elf at the offset,
185 // that the full file is used.
TEST_F(MapInfoGetElfTest,file_backed_non_zero_offset_full_file)186 TEST_F(MapInfoGetElfTest, file_backed_non_zero_offset_full_file) {
187   MapInfo info(nullptr, nullptr, 0x1000, 0x2000, 0x100, PROT_READ, elf_.path);
188 
189   std::vector<uint8_t> buffer(0x1000);
190   memset(buffer.data(), 0, buffer.size());
191   Elf32_Ehdr ehdr;
192   TestInitEhdr<Elf32_Ehdr>(&ehdr, ELFCLASS32, EM_ARM);
193   memcpy(buffer.data(), &ehdr, sizeof(ehdr));
194   ASSERT_TRUE(android::base::WriteFully(elf_.fd, buffer.data(), buffer.size()));
195 
196   Elf* elf = info.GetElf(process_memory_, ARCH_ARM);
197   ASSERT_TRUE(elf != nullptr);
198   ASSERT_TRUE(elf->valid());
199   ASSERT_TRUE(elf->memory() != nullptr);
200   ASSERT_EQ(0x100U, info.elf_offset());
201 
202   // Read the entire file.
203   memset(buffer.data(), 0, buffer.size());
204   ASSERT_TRUE(elf->memory()->ReadFully(0, buffer.data(), buffer.size()));
205   ASSERT_EQ(0, memcmp(buffer.data(), &ehdr, sizeof(ehdr)));
206   for (size_t i = sizeof(ehdr); i < buffer.size(); i++) {
207     ASSERT_EQ(0, buffer[i]) << "Failed at byte " << i;
208   }
209 
210   ASSERT_FALSE(elf->memory()->ReadFully(buffer.size(), buffer.data(), 1));
211 }
212 
213 // Verify that if the offset is non-zero and there is an elf at that
214 // offset, that only part of the file is used.
TEST_F(MapInfoGetElfTest,file_backed_non_zero_offset_partial_file)215 TEST_F(MapInfoGetElfTest, file_backed_non_zero_offset_partial_file) {
216   MapInfo info(nullptr, nullptr, 0x1000, 0x2000, 0x2000, PROT_READ, elf_.path);
217 
218   std::vector<uint8_t> buffer(0x4000);
219   memset(buffer.data(), 0, buffer.size());
220   Elf32_Ehdr ehdr;
221   TestInitEhdr<Elf32_Ehdr>(&ehdr, ELFCLASS32, EM_ARM);
222   memcpy(&buffer[info.offset()], &ehdr, sizeof(ehdr));
223   ASSERT_TRUE(android::base::WriteFully(elf_.fd, buffer.data(), buffer.size()));
224 
225   Elf* elf = info.GetElf(process_memory_, ARCH_ARM);
226   ASSERT_TRUE(elf != nullptr);
227   ASSERT_TRUE(elf->valid());
228   ASSERT_TRUE(elf->memory() != nullptr);
229   ASSERT_EQ(0U, info.elf_offset());
230 
231   // Read the valid part of the file.
232   ASSERT_TRUE(elf->memory()->ReadFully(0, buffer.data(), 0x1000));
233   ASSERT_EQ(0, memcmp(buffer.data(), &ehdr, sizeof(ehdr)));
234   for (size_t i = sizeof(ehdr); i < 0x1000; i++) {
235     ASSERT_EQ(0, buffer[i]) << "Failed at byte " << i;
236   }
237 
238   ASSERT_FALSE(elf->memory()->ReadFully(0x1000, buffer.data(), 1));
239 }
240 
241 // Verify that if the offset is non-zero and there is an elf at that
242 // offset, that only part of the file is used. Further verify that if the
243 // embedded elf is bigger than the initial map, the new object is larger
244 // 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)245 TEST_F(MapInfoGetElfTest, file_backed_non_zero_offset_partial_file_whole_elf32) {
246   MapInfo info(nullptr, nullptr, 0x5000, 0x6000, 0x1000, PROT_READ, elf_.path);
247 
248   std::vector<uint8_t> buffer(0x4000);
249   memset(buffer.data(), 0, buffer.size());
250   Elf32_Ehdr ehdr;
251   TestInitEhdr<Elf32_Ehdr>(&ehdr, ELFCLASS32, EM_ARM);
252   ehdr.e_shoff = 0x2000;
253   ehdr.e_shentsize = sizeof(Elf32_Shdr) + 100;
254   ehdr.e_shnum = 4;
255   memcpy(&buffer[info.offset()], &ehdr, sizeof(ehdr));
256   ASSERT_TRUE(android::base::WriteFully(elf_.fd, buffer.data(), buffer.size()));
257 
258   Elf* elf = info.GetElf(process_memory_, ARCH_ARM);
259   ASSERT_TRUE(elf != nullptr);
260   ASSERT_TRUE(elf->valid());
261   ASSERT_TRUE(elf->memory() != nullptr);
262   ASSERT_EQ(0U, info.elf_offset());
263 
264   // Verify the memory is a valid elf.
265   memset(buffer.data(), 0, buffer.size());
266   ASSERT_TRUE(elf->memory()->ReadFully(0, buffer.data(), 0x1000));
267   ASSERT_EQ(0, memcmp(buffer.data(), &ehdr, sizeof(ehdr)));
268 
269   // Read past the end of what would normally be the size of the map.
270   ASSERT_TRUE(elf->memory()->ReadFully(0x1000, buffer.data(), 1));
271 }
272 
TEST_F(MapInfoGetElfTest,file_backed_non_zero_offset_partial_file_whole_elf64)273 TEST_F(MapInfoGetElfTest, file_backed_non_zero_offset_partial_file_whole_elf64) {
274   MapInfo info(nullptr, nullptr, 0x7000, 0x8000, 0x1000, PROT_READ, elf_.path);
275 
276   std::vector<uint8_t> buffer(0x4000);
277   memset(buffer.data(), 0, buffer.size());
278   Elf64_Ehdr ehdr;
279   TestInitEhdr<Elf64_Ehdr>(&ehdr, ELFCLASS64, EM_AARCH64);
280   ehdr.e_shoff = 0x2000;
281   ehdr.e_shentsize = sizeof(Elf64_Shdr) + 100;
282   ehdr.e_shnum = 4;
283   memcpy(&buffer[info.offset()], &ehdr, sizeof(ehdr));
284   ASSERT_TRUE(android::base::WriteFully(elf_.fd, buffer.data(), buffer.size()));
285 
286   Elf* elf = info.GetElf(process_memory_, ARCH_ARM64);
287   ASSERT_TRUE(elf != nullptr);
288   ASSERT_TRUE(elf->valid());
289   ASSERT_TRUE(elf->memory() != nullptr);
290   ASSERT_EQ(0U, info.elf_offset());
291 
292   // Verify the memory is a valid elf.
293   memset(buffer.data(), 0, buffer.size());
294   ASSERT_TRUE(elf->memory()->ReadFully(0, buffer.data(), 0x1000));
295   ASSERT_EQ(0, memcmp(buffer.data(), &ehdr, sizeof(ehdr)));
296 
297   // Read past the end of what would normally be the size of the map.
298   ASSERT_TRUE(elf->memory()->ReadFully(0x1000, buffer.data(), 1));
299 }
300 
TEST_F(MapInfoGetElfTest,check_device_maps)301 TEST_F(MapInfoGetElfTest, check_device_maps) {
302   MapInfo info(nullptr, nullptr, 0x7000, 0x8000, 0x1000, PROT_READ | MAPS_FLAGS_DEVICE_MAP,
303                "/dev/something");
304 
305   // Create valid elf data in process memory for this to verify that only
306   // the name is causing invalid elf data.
307   Elf64_Ehdr ehdr;
308   TestInitEhdr<Elf64_Ehdr>(&ehdr, ELFCLASS64, EM_X86_64);
309   ehdr.e_shoff = 0x2000;
310   ehdr.e_shentsize = sizeof(Elf64_Shdr) + 100;
311   ehdr.e_shnum = 0;
312   memory_->SetMemory(0x7000, &ehdr, sizeof(ehdr));
313 
314   Elf* elf = info.GetElf(process_memory_, ARCH_X86_64);
315   ASSERT_TRUE(elf != nullptr);
316   ASSERT_FALSE(elf->valid());
317 
318   // Set the name to nothing to verify that it still fails.
319   info.set_elf(nullptr);
320   info.set_name("");
321   elf = info.GetElf(process_memory_, ARCH_X86_64);
322   ASSERT_FALSE(elf->valid());
323 
324   // Change the flags and verify the elf is valid now.
325   info.set_elf(nullptr);
326   info.set_flags(PROT_READ);
327   elf = info.GetElf(process_memory_, ARCH_X86_64);
328   ASSERT_TRUE(elf->valid());
329 }
330 
TEST_F(MapInfoGetElfTest,multiple_thread_get_elf)331 TEST_F(MapInfoGetElfTest, multiple_thread_get_elf) {
332   static constexpr size_t kNumConcurrentThreads = 100;
333 
334   Elf64_Ehdr ehdr;
335   TestInitEhdr<Elf64_Ehdr>(&ehdr, ELFCLASS64, EM_X86_64);
336   ehdr.e_shoff = 0x2000;
337   ehdr.e_shentsize = sizeof(Elf64_Shdr) + 100;
338   ehdr.e_shnum = 0;
339   memory_->SetMemory(0x7000, &ehdr, sizeof(ehdr));
340 
341   Elf* elf_in_threads[kNumConcurrentThreads];
342   std::vector<std::thread*> threads;
343 
344   std::atomic_bool wait;
345   wait = true;
346   // Create all of the threads and have them do the GetElf at the same time
347   // to make it likely that a race will occur.
348   MapInfo info(nullptr, nullptr, 0x7000, 0x8000, 0x1000, PROT_READ, "");
349   for (size_t i = 0; i < kNumConcurrentThreads; i++) {
350     std::thread* thread = new std::thread([i, this, &wait, &info, &elf_in_threads]() {
351       while (wait)
352         ;
353       Elf* elf = info.GetElf(process_memory_, ARCH_X86_64);
354       elf_in_threads[i] = elf;
355     });
356     threads.push_back(thread);
357   }
358   ASSERT_TRUE(info.elf() == nullptr);
359 
360   // Set them all going and wait for the threads to finish.
361   wait = false;
362   for (auto thread : threads) {
363     thread->join();
364     delete thread;
365   }
366 
367   // Now verify that all of the elf files are exactly the same and valid.
368   Elf* elf = info.elf().get();
369   ASSERT_TRUE(elf != nullptr);
370   EXPECT_TRUE(elf->valid());
371   for (size_t i = 0; i < kNumConcurrentThreads; i++) {
372     EXPECT_EQ(elf, elf_in_threads[i]) << "Thread " << i << " mismatched.";
373   }
374 }
375 
376 // Verify that previous maps don't automatically get the same elf object.
TEST_F(MapInfoGetElfTest,prev_map_elf_not_set)377 TEST_F(MapInfoGetElfTest, prev_map_elf_not_set) {
378   MapInfo info1(nullptr, nullptr, 0x1000, 0x2000, 0, PROT_READ, "/not/present");
379   MapInfo info2(&info1, &info1, 0x2000, 0x3000, 0, PROT_READ, elf_.path);
380 
381   Elf32_Ehdr ehdr;
382   TestInitEhdr<Elf32_Ehdr>(&ehdr, ELFCLASS32, EM_ARM);
383   memory_->SetMemory(0x2000, &ehdr, sizeof(ehdr));
384   Elf* elf = info2.GetElf(process_memory_, ARCH_ARM);
385   ASSERT_TRUE(elf != nullptr);
386   ASSERT_TRUE(elf->valid());
387 
388   ASSERT_NE(elf, info1.GetElf(process_memory_, ARCH_ARM));
389 }
390 
InitMapInfo(std::vector<std::unique_ptr<MapInfo>> & maps,bool in_memory)391 void MapInfoGetElfTest::InitMapInfo(std::vector<std::unique_ptr<MapInfo>>& maps, bool in_memory) {
392   maps.resize(2);
393   maps[0].reset(new MapInfo(nullptr, nullptr, 0x1000, 0x2000, 0, PROT_READ, elf_.path));
394   maps[1].reset(new MapInfo(maps[0].get(), maps[0].get(), 0x2000, 0x3000, 0x1000,
395                             PROT_READ | PROT_EXEC, elf_.path));
396 
397   Elf32_Ehdr ehdr;
398   TestInitEhdr<Elf32_Ehdr>(&ehdr, ELFCLASS32, EM_ARM);
399   if (in_memory) {
400     memory_->SetMemory(0x1000, &ehdr, sizeof(ehdr));
401   } else {
402     ASSERT_TRUE(android::base::WriteFully(elf_.fd, &ehdr, sizeof(ehdr)));
403   }
404 }
405 
406 // Verify that a read-only map followed by a read-execute map will result
407 // in the same elf object in both maps.
TEST_F(MapInfoGetElfTest,read_only_followed_by_read_exec_share_elf_exec_first)408 TEST_F(MapInfoGetElfTest, read_only_followed_by_read_exec_share_elf_exec_first) {
409   std::vector<std::unique_ptr<MapInfo>> maps;
410 
411   // First use in memory maps.
412   InitMapInfo(maps, true);
413   ASSERT_EQ(2U, maps.size());
414   MapInfo* r_map_info = maps[0].get();
415   MapInfo* rx_map_info = maps[1].get();
416 
417   // Get the elf from the read-exec map first.
418   Elf* elf = rx_map_info->GetElf(process_memory_, ARCH_ARM);
419   ASSERT_TRUE(elf != nullptr);
420   ASSERT_TRUE(elf->valid());
421 
422   ASSERT_EQ(elf, r_map_info->GetElf(process_memory_, ARCH_ARM));
423 
424   // Now use file maps.
425   maps.clear();
426   InitMapInfo(maps, false);
427   ASSERT_EQ(2U, maps.size());
428   r_map_info = maps[0].get();
429   rx_map_info = maps[1].get();
430 
431   // Get the elf from the read-exec map first.
432   elf = rx_map_info->GetElf(process_memory_, ARCH_ARM);
433   ASSERT_TRUE(elf != nullptr);
434   ASSERT_TRUE(elf->valid());
435 
436   ASSERT_EQ(elf, r_map_info->GetElf(process_memory_, ARCH_ARM));
437 }
438 
439 // Verify that a read-only map followed by a read-execute map will result
440 // in the same elf object in both maps.
TEST_F(MapInfoGetElfTest,read_only_followed_by_read_exec_share_elf_read_only_first)441 TEST_F(MapInfoGetElfTest, read_only_followed_by_read_exec_share_elf_read_only_first) {
442   std::vector<std::unique_ptr<MapInfo>> maps;
443 
444   // First use in memory maps.
445   InitMapInfo(maps, true);
446   ASSERT_EQ(2U, maps.size());
447   MapInfo* r_map_info = maps[0].get();
448   MapInfo* rx_map_info = maps[1].get();
449 
450   // Get the elf from the read-only map first.
451   Elf* elf = r_map_info->GetElf(process_memory_, ARCH_ARM);
452   ASSERT_TRUE(elf != nullptr);
453   ASSERT_TRUE(elf->valid());
454 
455   ASSERT_EQ(elf, rx_map_info->GetElf(process_memory_, ARCH_ARM));
456 
457   // Now use file maps.
458   maps.clear();
459   InitMapInfo(maps, false);
460   ASSERT_EQ(2U, maps.size());
461   r_map_info = maps[0].get();
462   rx_map_info = maps[1].get();
463 
464   // Get the elf from the read-only map first.
465   elf = r_map_info->GetElf(process_memory_, ARCH_ARM);
466   ASSERT_TRUE(elf != nullptr);
467   ASSERT_TRUE(elf->valid());
468 
469   ASSERT_EQ(elf, rx_map_info->GetElf(process_memory_, ARCH_ARM));
470 }
471 
472 // Verify that a read-only map followed by an empty map, then followed by
473 // a read-execute map will result in the same elf object in both maps.
TEST_F(MapInfoGetElfTest,read_only_followed_by_empty_then_read_exec_share_elf)474 TEST_F(MapInfoGetElfTest, read_only_followed_by_empty_then_read_exec_share_elf) {
475   MapInfo r_info(nullptr, nullptr, 0x1000, 0x2000, 0, PROT_READ, elf_.path);
476   MapInfo empty(&r_info, &r_info, 0x2000, 0x3000, 0, 0, "");
477   MapInfo rw_info(&empty, &r_info, 0x3000, 0x4000, 0x2000, PROT_READ | PROT_EXEC, elf_.path);
478 
479   Elf32_Ehdr ehdr;
480   TestInitEhdr<Elf32_Ehdr>(&ehdr, ELFCLASS32, EM_ARM);
481   memory_->SetMemory(0x1000, &ehdr, sizeof(ehdr));
482   Elf* elf = rw_info.GetElf(process_memory_, ARCH_ARM);
483   ASSERT_TRUE(elf != nullptr);
484   ASSERT_TRUE(elf->valid());
485 
486   ASSERT_EQ(elf, r_info.GetElf(process_memory_, ARCH_ARM));
487 }
488 
489 }  // namespace unwindstack
490