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