xref: /aosp_15_r20/system/unwinding/libunwindstack/tests/MapInfoGetElfTest.cpp (revision eb293b8f56ee8303637c5595cfcdeef8039e85c6)
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 "utils/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::shared_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   auto info = MapInfo::Create(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   Elf32_Ehdr ehdr;
83   TestInitEhdr<Elf32_Ehdr>(&ehdr, ELFCLASS32, EM_ARM);
84   memory_->SetMemory(0x3000, &ehdr, sizeof(ehdr));
85 
86   auto info = MapInfo::Create(0x3000, 0x4000, 0, PROT_READ, "");
87   Elf* elf = info->GetElf(process_memory_, ARCH_ARM);
88   ASSERT_TRUE(elf != nullptr);
89   ASSERT_TRUE(elf->valid());
90   EXPECT_EQ(static_cast<uint32_t>(EM_ARM), elf->machine_type());
91   EXPECT_EQ(ELFCLASS32, elf->class_type());
92 
93   // Now verify that an empty process memory returns an invalid elf object.
94   info->set_elf(nullptr);
95   elf = info->GetElf(std::shared_ptr<Memory>(), ARCH_ARM);
96   ASSERT_TRUE(elf != nullptr);
97   ASSERT_FALSE(elf->valid());
98 }
99 
TEST_F(MapInfoGetElfTest,valid64)100 TEST_F(MapInfoGetElfTest, valid64) {
101   Elf64_Ehdr ehdr;
102   TestInitEhdr<Elf64_Ehdr>(&ehdr, ELFCLASS64, EM_AARCH64);
103   memory_->SetMemory(0x8000, &ehdr, sizeof(ehdr));
104 
105   auto info = MapInfo::Create(0x8000, 0x9000, 0, PROT_READ, "");
106   Elf* elf = info->GetElf(process_memory_, ARCH_ARM64);
107   ASSERT_TRUE(elf != nullptr);
108   ASSERT_TRUE(elf->valid());
109   EXPECT_EQ(static_cast<uint32_t>(EM_AARCH64), elf->machine_type());
110   EXPECT_EQ(ELFCLASS64, elf->class_type());
111 }
112 
TEST_F(MapInfoGetElfTest,invalid_arch_mismatch)113 TEST_F(MapInfoGetElfTest, invalid_arch_mismatch) {
114   Elf32_Ehdr ehdr;
115   TestInitEhdr<Elf32_Ehdr>(&ehdr, ELFCLASS32, EM_ARM);
116   memory_->SetMemory(0x3000, &ehdr, sizeof(ehdr));
117 
118   auto info = MapInfo::Create(0x3000, 0x4000, 0, PROT_READ, "");
119   Elf* elf = info->GetElf(process_memory_, ARCH_X86);
120   ASSERT_TRUE(elf != nullptr);
121   ASSERT_FALSE(elf->valid());
122 }
123 
TEST_F(MapInfoGetElfTest,gnu_debugdata_init32)124 TEST_F(MapInfoGetElfTest, gnu_debugdata_init32) {
125   TestInitGnuDebugdata<Elf32_Ehdr, Elf32_Shdr>(ELFCLASS32, EM_ARM, true,
126                                                [&](uint64_t offset, const void* ptr, size_t size) {
127                                                  memory_->SetMemory(0x2000 + offset, ptr, size);
128                                                });
129 
130   auto info = MapInfo::Create(0x2000, 0x3000, 0, PROT_READ, "");
131   Elf* elf = info->GetElf(process_memory_, ARCH_ARM);
132   ASSERT_TRUE(elf != nullptr);
133   ASSERT_TRUE(elf->valid());
134   EXPECT_EQ(static_cast<uint32_t>(EM_ARM), elf->machine_type());
135   EXPECT_EQ(ELFCLASS32, elf->class_type());
136   EXPECT_TRUE(elf->gnu_debugdata_interface() != nullptr);
137 }
138 
TEST_F(MapInfoGetElfTest,gnu_debugdata_init64)139 TEST_F(MapInfoGetElfTest, gnu_debugdata_init64) {
140   TestInitGnuDebugdata<Elf64_Ehdr, Elf64_Shdr>(ELFCLASS64, EM_AARCH64, true,
141                                                [&](uint64_t offset, const void* ptr, size_t size) {
142                                                  memory_->SetMemory(0x5000 + offset, ptr, size);
143                                                });
144 
145   auto info = MapInfo::Create(0x5000, 0x8000, 0, PROT_READ, "");
146   Elf* elf = info->GetElf(process_memory_, ARCH_ARM64);
147   ASSERT_TRUE(elf != nullptr);
148   ASSERT_TRUE(elf->valid());
149   EXPECT_EQ(static_cast<uint32_t>(EM_AARCH64), elf->machine_type());
150   EXPECT_EQ(ELFCLASS64, elf->class_type());
151   EXPECT_TRUE(elf->gnu_debugdata_interface() != nullptr);
152 }
153 
TEST_F(MapInfoGetElfTest,end_le_start)154 TEST_F(MapInfoGetElfTest, end_le_start) {
155   Elf32_Ehdr ehdr;
156   TestInitEhdr<Elf32_Ehdr>(&ehdr, ELFCLASS32, EM_ARM);
157   ASSERT_TRUE(android::base::WriteFully(elf_.fd, &ehdr, sizeof(ehdr)));
158 
159   auto info = MapInfo::Create(0x1000, 0x1000, 0, PROT_READ, elf_.path);
160   Elf* elf = info->GetElf(process_memory_, ARCH_ARM);
161   ASSERT_TRUE(elf != nullptr);
162   ASSERT_FALSE(elf->valid());
163 
164   info->set_elf(nullptr);
165   info->set_end(0xfff);
166   elf = info->GetElf(process_memory_, ARCH_ARM);
167   ASSERT_TRUE(elf != nullptr);
168   ASSERT_FALSE(elf->valid());
169 
170   // Make sure this test is valid.
171   info->set_elf(nullptr);
172   info->set_end(0x2000);
173   elf = info->GetElf(process_memory_, ARCH_ARM);
174   ASSERT_TRUE(elf != nullptr);
175   ASSERT_TRUE(elf->valid());
176 }
177 
178 // Verify that if the offset is non-zero but there is no elf at the offset,
179 // that the full file is used.
TEST_F(MapInfoGetElfTest,file_backed_non_zero_offset_full_file)180 TEST_F(MapInfoGetElfTest, file_backed_non_zero_offset_full_file) {
181   std::vector<uint8_t> buffer(0x1000);
182   memset(buffer.data(), 0, buffer.size());
183   Elf32_Ehdr ehdr;
184   TestInitEhdr<Elf32_Ehdr>(&ehdr, ELFCLASS32, EM_ARM);
185   memcpy(buffer.data(), &ehdr, sizeof(ehdr));
186   ASSERT_TRUE(android::base::WriteFully(elf_.fd, buffer.data(), buffer.size()));
187 
188   auto info = MapInfo::Create(0x1000, 0x2000, 0x100, PROT_READ, elf_.path);
189   Elf* elf = info->GetElf(process_memory_, ARCH_ARM);
190   ASSERT_TRUE(elf != nullptr);
191   ASSERT_TRUE(elf->valid());
192   ASSERT_TRUE(elf->memory() != nullptr);
193   ASSERT_EQ(0x100U, info->elf_offset());
194 
195   // Read the entire file.
196   memset(buffer.data(), 0, buffer.size());
197   ASSERT_TRUE(elf->memory()->ReadFully(0, buffer.data(), buffer.size()));
198   ASSERT_EQ(0, memcmp(buffer.data(), &ehdr, sizeof(ehdr)));
199   for (size_t i = sizeof(ehdr); i < buffer.size(); i++) {
200     ASSERT_EQ(0, buffer[i]) << "Failed at byte " << i;
201   }
202 
203   ASSERT_FALSE(elf->memory()->ReadFully(buffer.size(), buffer.data(), 1));
204 }
205 
206 // Verify that if the offset is non-zero and there is an elf at that
207 // offset, that only part of the file is used.
TEST_F(MapInfoGetElfTest,file_backed_non_zero_offset_partial_file)208 TEST_F(MapInfoGetElfTest, file_backed_non_zero_offset_partial_file) {
209   auto info = MapInfo::Create(0x1000, 0x2000, 0x2000, PROT_READ, elf_.path);
210 
211   std::vector<uint8_t> buffer(0x4000);
212   memset(buffer.data(), 0, buffer.size());
213   Elf32_Ehdr ehdr;
214   TestInitEhdr<Elf32_Ehdr>(&ehdr, ELFCLASS32, EM_ARM);
215   memcpy(&buffer[info->offset()], &ehdr, sizeof(ehdr));
216   ASSERT_TRUE(android::base::WriteFully(elf_.fd, buffer.data(), buffer.size()));
217 
218   Elf* elf = info->GetElf(process_memory_, ARCH_ARM);
219   ASSERT_TRUE(elf != nullptr);
220   ASSERT_TRUE(elf->valid());
221   ASSERT_TRUE(elf->memory() != nullptr);
222   ASSERT_EQ(0U, info->elf_offset());
223 
224   // Read the valid part of the file.
225   ASSERT_TRUE(elf->memory()->ReadFully(0, buffer.data(), 0x1000));
226   ASSERT_EQ(0, memcmp(buffer.data(), &ehdr, sizeof(ehdr)));
227   for (size_t i = sizeof(ehdr); i < 0x1000; i++) {
228     ASSERT_EQ(0, buffer[i]) << "Failed at byte " << i;
229   }
230 
231   ASSERT_FALSE(elf->memory()->ReadFully(0x1000, buffer.data(), 1));
232 }
233 
234 // Verify that if the offset is non-zero and there is an elf at that
235 // offset, that only part of the file is used. Further verify that if the
236 // embedded elf is bigger than the initial map, the new object is larger
237 // 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)238 TEST_F(MapInfoGetElfTest, file_backed_non_zero_offset_partial_file_whole_elf32) {
239   auto info = MapInfo::Create(0x5000, 0x6000, 0x1000, PROT_READ, elf_.path);
240 
241   std::vector<uint8_t> buffer(0x4000);
242   memset(buffer.data(), 0, buffer.size());
243   Elf32_Ehdr ehdr;
244   TestInitEhdr<Elf32_Ehdr>(&ehdr, ELFCLASS32, EM_ARM);
245   ehdr.e_shoff = 0x2000;
246   ehdr.e_shentsize = sizeof(Elf32_Shdr) + 100;
247   ehdr.e_shnum = 4;
248   memcpy(&buffer[info->offset()], &ehdr, sizeof(ehdr));
249   ASSERT_TRUE(android::base::WriteFully(elf_.fd, buffer.data(), buffer.size()));
250 
251   Elf* elf = info->GetElf(process_memory_, ARCH_ARM);
252   ASSERT_TRUE(elf != nullptr);
253   ASSERT_TRUE(elf->valid());
254   ASSERT_TRUE(elf->memory() != nullptr);
255   ASSERT_EQ(0U, info->elf_offset());
256 
257   // Verify the memory is a valid elf.
258   memset(buffer.data(), 0, buffer.size());
259   ASSERT_TRUE(elf->memory()->ReadFully(0, buffer.data(), 0x1000));
260   ASSERT_EQ(0, memcmp(buffer.data(), &ehdr, sizeof(ehdr)));
261 
262   // Read past the end of what would normally be the size of the map.
263   ASSERT_TRUE(elf->memory()->ReadFully(0x1000, buffer.data(), 1));
264 }
265 
TEST_F(MapInfoGetElfTest,file_backed_non_zero_offset_partial_file_whole_elf64)266 TEST_F(MapInfoGetElfTest, file_backed_non_zero_offset_partial_file_whole_elf64) {
267   auto info = MapInfo::Create(0x7000, 0x8000, 0x1000, PROT_READ, elf_.path);
268 
269   std::vector<uint8_t> buffer(0x4000);
270   memset(buffer.data(), 0, buffer.size());
271   Elf64_Ehdr ehdr;
272   TestInitEhdr<Elf64_Ehdr>(&ehdr, ELFCLASS64, EM_AARCH64);
273   ehdr.e_shoff = 0x2000;
274   ehdr.e_shentsize = sizeof(Elf64_Shdr) + 100;
275   ehdr.e_shnum = 4;
276   memcpy(&buffer[info->offset()], &ehdr, sizeof(ehdr));
277   ASSERT_TRUE(android::base::WriteFully(elf_.fd, buffer.data(), buffer.size()));
278 
279   Elf* elf = info->GetElf(process_memory_, ARCH_ARM64);
280   ASSERT_TRUE(elf != nullptr);
281   ASSERT_TRUE(elf->valid());
282   ASSERT_TRUE(elf->memory() != nullptr);
283   ASSERT_EQ(0U, info->elf_offset());
284 
285   // Verify the memory is a valid elf.
286   memset(buffer.data(), 0, buffer.size());
287   ASSERT_TRUE(elf->memory()->ReadFully(0, buffer.data(), 0x1000));
288   ASSERT_EQ(0, memcmp(buffer.data(), &ehdr, sizeof(ehdr)));
289 
290   // Read past the end of what would normally be the size of the map.
291   ASSERT_TRUE(elf->memory()->ReadFully(0x1000, buffer.data(), 1));
292 }
293 
294 // Verify that if the offset is non-zero and there is an elf at that
295 // offset, that only part of the file is used. Further verify that if the
296 // the initial map is smaller than elf header size, we can still read the elf.
TEST_F(MapInfoGetElfTest,file_backed_non_zero_offset_partial_file_whole_elf64_small_map_range)297 TEST_F(MapInfoGetElfTest, file_backed_non_zero_offset_partial_file_whole_elf64_small_map_range) {
298   auto info = MapInfo::Create(0x7000, 0x7004, 0x1000, PROT_READ, elf_.path);
299 
300   std::vector<uint8_t> buffer(0x4000);
301   memset(buffer.data(), 0, buffer.size());
302   Elf64_Ehdr ehdr;
303   TestInitEhdr<Elf64_Ehdr>(&ehdr, ELFCLASS64, EM_AARCH64);
304   ehdr.e_shoff = 0x2000;
305   ehdr.e_shentsize = sizeof(Elf64_Shdr) + 100;
306   ehdr.e_shnum = 4;
307   memcpy(&buffer[info->offset()], &ehdr, sizeof(ehdr));
308   ASSERT_TRUE(android::base::WriteFully(elf_.fd, buffer.data(), buffer.size()));
309 
310   Elf* elf = info->GetElf(process_memory_, ARCH_ARM64);
311   ASSERT_TRUE(elf != nullptr);
312   ASSERT_TRUE(elf->valid());
313   ASSERT_TRUE(elf->memory() != nullptr);
314   ASSERT_EQ(0U, info->elf_offset());
315 
316   // Verify the memory is a valid elf.
317   memset(buffer.data(), 0, buffer.size());
318   ASSERT_TRUE(elf->memory()->ReadFully(0, buffer.data(), 0x1000));
319   ASSERT_EQ(0, memcmp(buffer.data(), &ehdr, sizeof(ehdr)));
320 
321   // Read past the end of what would normally be the size of the map.
322   ASSERT_TRUE(elf->memory()->ReadFully(0x1000, buffer.data(), 1));
323 }
324 
TEST_F(MapInfoGetElfTest,check_device_maps)325 TEST_F(MapInfoGetElfTest, check_device_maps) {
326   // Create valid elf data in process memory for this to verify that only
327   // the name is causing invalid elf data.
328   Elf64_Ehdr ehdr;
329   TestInitEhdr<Elf64_Ehdr>(&ehdr, ELFCLASS64, EM_X86_64);
330   ehdr.e_shoff = 0x2000;
331   ehdr.e_shentsize = sizeof(Elf64_Shdr) + 100;
332   ehdr.e_shnum = 0;
333   memory_->SetMemory(0x7000, &ehdr, sizeof(ehdr));
334 
335   auto info =
336       MapInfo::Create(0x7000, 0x8000, 0x1000, PROT_READ | MAPS_FLAGS_DEVICE_MAP, "/dev/something");
337   Elf* elf = info->GetElf(process_memory_, ARCH_X86_64);
338   ASSERT_TRUE(elf != nullptr);
339   ASSERT_FALSE(elf->valid());
340 
341   // Set the name to nothing to verify that it still fails.
342   info->set_elf(nullptr);
343   info->set_name("");
344   elf = info->GetElf(process_memory_, ARCH_X86_64);
345   ASSERT_FALSE(elf->valid());
346 
347   // Change the flags and verify the elf is valid now.
348   info->set_elf(nullptr);
349   info->set_flags(PROT_READ);
350   elf = info->GetElf(process_memory_, ARCH_X86_64);
351   ASSERT_TRUE(elf->valid());
352 }
353 
TEST_F(MapInfoGetElfTest,multiple_thread_get_elf)354 TEST_F(MapInfoGetElfTest, multiple_thread_get_elf) {
355   static constexpr size_t kNumConcurrentThreads = 100;
356 
357   Elf64_Ehdr ehdr;
358   TestInitEhdr<Elf64_Ehdr>(&ehdr, ELFCLASS64, EM_X86_64);
359   ehdr.e_shoff = 0x2000;
360   ehdr.e_shentsize = sizeof(Elf64_Shdr) + 100;
361   ehdr.e_shnum = 0;
362   memory_->SetMemory(0x7000, &ehdr, sizeof(ehdr));
363 
364   Elf* elf_in_threads[kNumConcurrentThreads];
365   std::vector<std::thread*> threads;
366 
367   std::atomic_bool wait;
368   wait = true;
369   // Create all of the threads and have them do the GetElf at the same time
370   // to make it likely that a race will occur.
371   auto info = MapInfo::Create(0x7000, 0x8000, 0x1000, PROT_READ, "");
372   for (size_t i = 0; i < kNumConcurrentThreads; i++) {
373     std::thread* thread = new std::thread([i, this, &wait, &info, &elf_in_threads]() {
374       while (wait)
375         ;
376       Elf* elf = info->GetElf(process_memory_, ARCH_X86_64);
377       elf_in_threads[i] = elf;
378     });
379     threads.push_back(thread);
380   }
381   ASSERT_TRUE(info->elf() == nullptr);
382 
383   // Set them all going and wait for the threads to finish.
384   wait = false;
385   for (auto thread : threads) {
386     thread->join();
387     delete thread;
388   }
389 
390   // Now verify that all of the elf files are exactly the same and valid.
391   Elf* elf = info->elf().get();
392   ASSERT_TRUE(elf != nullptr);
393   EXPECT_TRUE(elf->valid());
394   for (size_t i = 0; i < kNumConcurrentThreads; i++) {
395     EXPECT_EQ(elf, elf_in_threads[i]) << "Thread " << i << " mismatched.";
396   }
397 }
398 
399 // Verify that previous maps don't automatically get the same elf object.
TEST_F(MapInfoGetElfTest,prev_map_elf_not_set)400 TEST_F(MapInfoGetElfTest, prev_map_elf_not_set) {
401   auto info1 = MapInfo::Create(0x1000, 0x2000, 0, PROT_READ, "/not/present");
402   auto info2 = MapInfo::Create(info1, 0x2000, 0x3000, 0, PROT_READ, elf_.path);
403 
404   Elf32_Ehdr ehdr;
405   TestInitEhdr<Elf32_Ehdr>(&ehdr, ELFCLASS32, EM_ARM);
406   memory_->SetMemory(0x2000, &ehdr, sizeof(ehdr));
407   Elf* elf = info2->GetElf(process_memory_, ARCH_ARM);
408   ASSERT_TRUE(elf != nullptr);
409   ASSERT_TRUE(elf->valid());
410 
411   ASSERT_NE(elf, info1->GetElf(process_memory_, ARCH_ARM));
412 }
413 
InitMapInfo(std::vector<std::shared_ptr<MapInfo>> & maps,bool in_memory)414 void MapInfoGetElfTest::InitMapInfo(std::vector<std::shared_ptr<MapInfo>>& maps, bool in_memory) {
415   maps.resize(2);
416   maps[0] = MapInfo::Create(0x1000, 0x2000, 0, PROT_READ, elf_.path);
417   maps[1] = MapInfo::Create(maps[0], 0x2000, 0x3000, 0x1000, PROT_READ | PROT_EXEC, elf_.path);
418 
419   Elf32_Ehdr ehdr;
420   TestInitEhdr<Elf32_Ehdr>(&ehdr, ELFCLASS32, EM_ARM);
421   if (in_memory) {
422     memory_->SetMemory(0x1000, &ehdr, sizeof(ehdr));
423   } else {
424     ASSERT_TRUE(android::base::WriteFully(elf_.fd, &ehdr, sizeof(ehdr)));
425   }
426 }
427 
428 // Verify that a read-only map followed by a read-execute map will result
429 // in the same elf object in both maps.
TEST_F(MapInfoGetElfTest,read_only_followed_by_read_exec_share_elf_exec_first)430 TEST_F(MapInfoGetElfTest, read_only_followed_by_read_exec_share_elf_exec_first) {
431   std::vector<std::shared_ptr<MapInfo>> maps;
432 
433   // First use in memory maps.
434   InitMapInfo(maps, true);
435   ASSERT_EQ(2U, maps.size());
436   MapInfo* r_map_info = maps[0].get();
437   MapInfo* rx_map_info = maps[1].get();
438 
439   // Get the elf from the read-exec map first.
440   Elf* elf = rx_map_info->GetElf(process_memory_, ARCH_ARM);
441   ASSERT_TRUE(elf != nullptr);
442   ASSERT_TRUE(elf->valid());
443 
444   ASSERT_EQ(elf, r_map_info->GetElf(process_memory_, ARCH_ARM));
445 
446   // Now use file maps.
447   maps.clear();
448   InitMapInfo(maps, false);
449   ASSERT_EQ(2U, maps.size());
450   r_map_info = maps[0].get();
451   rx_map_info = maps[1].get();
452 
453   // Get the elf from the read-exec map first.
454   elf = rx_map_info->GetElf(process_memory_, ARCH_ARM);
455   ASSERT_TRUE(elf != nullptr);
456   ASSERT_TRUE(elf->valid());
457 
458   ASSERT_EQ(elf, r_map_info->GetElf(process_memory_, ARCH_ARM));
459 }
460 
461 // Verify that a read-only map followed by a read-execute map will result
462 // in the same elf object in both maps.
TEST_F(MapInfoGetElfTest,read_only_followed_by_read_exec_share_elf_read_only_first)463 TEST_F(MapInfoGetElfTest, read_only_followed_by_read_exec_share_elf_read_only_first) {
464   std::vector<std::shared_ptr<MapInfo>> maps;
465 
466   // First use in memory maps.
467   InitMapInfo(maps, true);
468   ASSERT_EQ(2U, maps.size());
469   MapInfo* r_map_info = maps[0].get();
470   MapInfo* rx_map_info = maps[1].get();
471 
472   // Get the elf from the read-only map first.
473   Elf* elf = r_map_info->GetElf(process_memory_, ARCH_ARM);
474   ASSERT_TRUE(elf != nullptr);
475   ASSERT_TRUE(elf->valid());
476 
477   ASSERT_EQ(elf, rx_map_info->GetElf(process_memory_, ARCH_ARM));
478 
479   // Now use file maps.
480   maps.clear();
481   InitMapInfo(maps, false);
482   ASSERT_EQ(2U, maps.size());
483   r_map_info = maps[0].get();
484   rx_map_info = maps[1].get();
485 
486   // Get the elf from the read-only map first.
487   elf = r_map_info->GetElf(process_memory_, ARCH_ARM);
488   ASSERT_TRUE(elf != nullptr);
489   ASSERT_TRUE(elf->valid());
490 
491   ASSERT_EQ(elf, rx_map_info->GetElf(process_memory_, ARCH_ARM));
492 }
493 
494 // Verify that a read-only map followed by an empty map, then followed by
495 // 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)496 TEST_F(MapInfoGetElfTest, read_only_followed_by_empty_then_read_exec_share_elf) {
497   auto r_info = MapInfo::Create(0x1000, 0x2000, 0, PROT_READ, elf_.path);
498   auto empty = MapInfo::Create(r_info, 0x2000, 0x3000, 0, 0, "");
499   auto rw_info = MapInfo::Create(empty, 0x3000, 0x4000, 0x2000, PROT_READ | PROT_EXEC, elf_.path);
500 
501   Elf32_Ehdr ehdr;
502   TestInitEhdr<Elf32_Ehdr>(&ehdr, ELFCLASS32, EM_ARM);
503   memory_->SetMemory(0x1000, &ehdr, sizeof(ehdr));
504   Elf* elf = rw_info->GetElf(process_memory_, ARCH_ARM);
505   ASSERT_TRUE(elf != nullptr);
506   ASSERT_TRUE(elf->valid());
507 
508   ASSERT_EQ(elf, r_info->GetElf(process_memory_, ARCH_ARM));
509 }
510 
511 }  // namespace unwindstack
512