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