blob: 9973794800fad744386c585377f3dd415c7911a4 [file] [log] [blame]
Christopher Ferris570b76f2017-06-30 17:18:16 -07001/*
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
Christopher Ferrisbe788d82017-11-27 14:50:38 -080026#include <atomic>
Christopher Ferris570b76f2017-06-30 17:18:16 -070027#include <memory>
Christopher Ferrisbe788d82017-11-27 14:50:38 -080028#include <thread>
Christopher Ferris570b76f2017-06-30 17:18:16 -070029#include <vector>
30
31#include <android-base/file.h>
32#include <android-base/test_utils.h>
33#include <gtest/gtest.h>
34
Christopher Ferrisd226a512017-07-14 10:37:19 -070035#include <unwindstack/Elf.h>
36#include <unwindstack/MapInfo.h>
Christopher Ferris5f118512017-09-01 11:17:16 -070037#include <unwindstack/Maps.h>
Christopher Ferrisd226a512017-07-14 10:37:19 -070038#include <unwindstack/Memory.h>
39
Christopher Ferris570b76f2017-06-30 17:18:16 -070040#include "ElfTestUtils.h"
Christopher Ferris5f118512017-09-01 11:17:16 -070041#include "MemoryFake.h"
Christopher Ferrisd226a512017-07-14 10:37:19 -070042
43namespace unwindstack {
Christopher Ferris570b76f2017-06-30 17:18:16 -070044
45class MapInfoGetElfTest : public ::testing::Test {
46 protected:
47 void SetUp() override {
Christopher Ferris5f118512017-09-01 11:17:16 -070048 memory_ = new MemoryFake;
49 process_memory_.reset(memory_);
Christopher Ferris570b76f2017-06-30 17:18:16 -070050 }
51
Christopher Ferris5f118512017-09-01 11:17:16 -070052 template <typename Ehdr, typename Shdr>
53 static void InitElf(uint64_t sh_offset, Ehdr* ehdr, uint8_t class_type, uint8_t machine_type) {
54 memset(ehdr, 0, sizeof(*ehdr));
55 memcpy(ehdr->e_ident, ELFMAG, SELFMAG);
56 ehdr->e_ident[EI_CLASS] = class_type;
57 ehdr->e_machine = machine_type;
58 ehdr->e_shoff = sh_offset;
59 ehdr->e_shentsize = sizeof(Shdr) + 100;
60 ehdr->e_shnum = 4;
61 }
Christopher Ferris570b76f2017-06-30 17:18:16 -070062
63 const size_t kMapSize = 4096;
64
Christopher Ferris5f118512017-09-01 11:17:16 -070065 std::shared_ptr<Memory> process_memory_;
66 MemoryFake* memory_;
67
68 TemporaryFile elf_;
Christopher Ferris570b76f2017-06-30 17:18:16 -070069};
70
71TEST_F(MapInfoGetElfTest, invalid) {
Christopher Ferrisbe788d82017-11-27 14:50:38 -080072 MapInfo info(0x1000, 0x2000, 0, PROT_READ, "");
Christopher Ferris5f118512017-09-01 11:17:16 -070073
Christopher Ferris570b76f2017-06-30 17:18:16 -070074 // The map is empty, but this should still create an invalid elf object.
Christopher Ferrisbe788d82017-11-27 14:50:38 -080075 Elf* elf = info.GetElf(process_memory_, false);
76 ASSERT_TRUE(elf != nullptr);
Christopher Ferris570b76f2017-06-30 17:18:16 -070077 ASSERT_FALSE(elf->valid());
78}
79
80TEST_F(MapInfoGetElfTest, valid32) {
Christopher Ferrisbe788d82017-11-27 14:50:38 -080081 MapInfo info(0x3000, 0x4000, 0, PROT_READ, "");
Christopher Ferris5f118512017-09-01 11:17:16 -070082
Christopher Ferris570b76f2017-06-30 17:18:16 -070083 Elf32_Ehdr ehdr;
84 TestInitEhdr<Elf32_Ehdr>(&ehdr, ELFCLASS32, EM_ARM);
Christopher Ferris5f118512017-09-01 11:17:16 -070085 memory_->SetMemory(0x3000, &ehdr, sizeof(ehdr));
Christopher Ferris570b76f2017-06-30 17:18:16 -070086
Christopher Ferrisbe788d82017-11-27 14:50:38 -080087 Elf* elf = info.GetElf(process_memory_, false);
88 ASSERT_TRUE(elf != nullptr);
Christopher Ferris570b76f2017-06-30 17:18:16 -070089 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
94TEST_F(MapInfoGetElfTest, valid64) {
Christopher Ferrisbe788d82017-11-27 14:50:38 -080095 MapInfo info(0x8000, 0x9000, 0, PROT_READ, "");
Christopher Ferris5f118512017-09-01 11:17:16 -070096
Christopher Ferris570b76f2017-06-30 17:18:16 -070097 Elf64_Ehdr ehdr;
98 TestInitEhdr<Elf64_Ehdr>(&ehdr, ELFCLASS64, EM_AARCH64);
Christopher Ferris5f118512017-09-01 11:17:16 -070099 memory_->SetMemory(0x8000, &ehdr, sizeof(ehdr));
Christopher Ferris570b76f2017-06-30 17:18:16 -0700100
Christopher Ferrisbe788d82017-11-27 14:50:38 -0800101 Elf* elf = info.GetElf(process_memory_, false);
102 ASSERT_TRUE(elf != nullptr);
Christopher Ferris570b76f2017-06-30 17:18:16 -0700103 ASSERT_TRUE(elf->valid());
104 EXPECT_EQ(static_cast<uint32_t>(EM_AARCH64), elf->machine_type());
105 EXPECT_EQ(ELFCLASS64, elf->class_type());
106}
107
108TEST_F(MapInfoGetElfTest, gnu_debugdata_do_not_init32) {
Christopher Ferrisbe788d82017-11-27 14:50:38 -0800109 MapInfo info(0x4000, 0x8000, 0, PROT_READ, "");
Christopher Ferris570b76f2017-06-30 17:18:16 -0700110
Christopher Ferris5f118512017-09-01 11:17:16 -0700111 TestInitGnuDebugdata<Elf32_Ehdr, Elf32_Shdr>(ELFCLASS32, EM_ARM, false,
112 [&](uint64_t offset, const void* ptr, size_t size) {
113 memory_->SetMemory(0x4000 + offset, ptr, size);
114 });
115
Christopher Ferrisbe788d82017-11-27 14:50:38 -0800116 Elf* elf = info.GetElf(process_memory_, false);
117 ASSERT_TRUE(elf != nullptr);
Christopher Ferris570b76f2017-06-30 17:18:16 -0700118 ASSERT_TRUE(elf->valid());
119 EXPECT_EQ(static_cast<uint32_t>(EM_ARM), elf->machine_type());
120 EXPECT_EQ(ELFCLASS32, elf->class_type());
121 EXPECT_TRUE(elf->gnu_debugdata_interface() == nullptr);
122}
123
124TEST_F(MapInfoGetElfTest, gnu_debugdata_do_not_init64) {
Christopher Ferrisbe788d82017-11-27 14:50:38 -0800125 MapInfo info(0x6000, 0x8000, 0, PROT_READ, "");
Christopher Ferris570b76f2017-06-30 17:18:16 -0700126
Christopher Ferris5f118512017-09-01 11:17:16 -0700127 TestInitGnuDebugdata<Elf64_Ehdr, Elf64_Shdr>(ELFCLASS64, EM_AARCH64, false,
128 [&](uint64_t offset, const void* ptr, size_t size) {
129 memory_->SetMemory(0x6000 + offset, ptr, size);
130 });
131
Christopher Ferrisbe788d82017-11-27 14:50:38 -0800132 Elf* elf = info.GetElf(process_memory_, false);
133 ASSERT_TRUE(elf != nullptr);
Christopher Ferris570b76f2017-06-30 17:18:16 -0700134 ASSERT_TRUE(elf->valid());
135 EXPECT_EQ(static_cast<uint32_t>(EM_AARCH64), elf->machine_type());
136 EXPECT_EQ(ELFCLASS64, elf->class_type());
137 EXPECT_TRUE(elf->gnu_debugdata_interface() == nullptr);
138}
139
140TEST_F(MapInfoGetElfTest, gnu_debugdata_init32) {
Christopher Ferrisbe788d82017-11-27 14:50:38 -0800141 MapInfo info(0x2000, 0x3000, 0, PROT_READ, "");
Christopher Ferris570b76f2017-06-30 17:18:16 -0700142
Christopher Ferris5f118512017-09-01 11:17:16 -0700143 TestInitGnuDebugdata<Elf32_Ehdr, Elf32_Shdr>(ELFCLASS32, EM_ARM, true,
144 [&](uint64_t offset, const void* ptr, size_t size) {
145 memory_->SetMemory(0x2000 + offset, ptr, size);
146 });
147
Christopher Ferrisbe788d82017-11-27 14:50:38 -0800148 Elf* elf = info.GetElf(process_memory_, true);
149 ASSERT_TRUE(elf != nullptr);
Christopher Ferris570b76f2017-06-30 17:18:16 -0700150 ASSERT_TRUE(elf->valid());
151 EXPECT_EQ(static_cast<uint32_t>(EM_ARM), elf->machine_type());
152 EXPECT_EQ(ELFCLASS32, elf->class_type());
153 EXPECT_TRUE(elf->gnu_debugdata_interface() != nullptr);
154}
155
156TEST_F(MapInfoGetElfTest, gnu_debugdata_init64) {
Christopher Ferrisbe788d82017-11-27 14:50:38 -0800157 MapInfo info(0x5000, 0x8000, 0, PROT_READ, "");
Christopher Ferris570b76f2017-06-30 17:18:16 -0700158
Christopher Ferris5f118512017-09-01 11:17:16 -0700159 TestInitGnuDebugdata<Elf64_Ehdr, Elf64_Shdr>(ELFCLASS64, EM_AARCH64, true,
160 [&](uint64_t offset, const void* ptr, size_t size) {
161 memory_->SetMemory(0x5000 + offset, ptr, size);
162 });
163
Christopher Ferrisbe788d82017-11-27 14:50:38 -0800164 Elf* elf = info.GetElf(process_memory_, true);
165 ASSERT_TRUE(elf != nullptr);
Christopher Ferris570b76f2017-06-30 17:18:16 -0700166 ASSERT_TRUE(elf->valid());
167 EXPECT_EQ(static_cast<uint32_t>(EM_AARCH64), elf->machine_type());
168 EXPECT_EQ(ELFCLASS64, elf->class_type());
169 EXPECT_TRUE(elf->gnu_debugdata_interface() != nullptr);
170}
Christopher Ferrisd226a512017-07-14 10:37:19 -0700171
Christopher Ferris5f118512017-09-01 11:17:16 -0700172TEST_F(MapInfoGetElfTest, end_le_start) {
Christopher Ferrisbe788d82017-11-27 14:50:38 -0800173 MapInfo info(0x1000, 0x1000, 0, PROT_READ, elf_.path);
Christopher Ferris5f118512017-09-01 11:17:16 -0700174
175 Elf32_Ehdr ehdr;
176 TestInitEhdr<Elf32_Ehdr>(&ehdr, ELFCLASS32, EM_ARM);
177 ASSERT_TRUE(android::base::WriteFully(elf_.fd, &ehdr, sizeof(ehdr)));
178
Christopher Ferrisbe788d82017-11-27 14:50:38 -0800179 Elf* elf = info.GetElf(process_memory_, false);
180 ASSERT_TRUE(elf != nullptr);
Christopher Ferris5f118512017-09-01 11:17:16 -0700181 ASSERT_FALSE(elf->valid());
182
Christopher Ferrisbe788d82017-11-27 14:50:38 -0800183 delete info.elf;
Christopher Ferris5f118512017-09-01 11:17:16 -0700184 info.elf = nullptr;
185 info.end = 0xfff;
Christopher Ferrisbe788d82017-11-27 14:50:38 -0800186 elf = info.GetElf(process_memory_, false);
187 ASSERT_TRUE(elf != nullptr);
Christopher Ferris5f118512017-09-01 11:17:16 -0700188 ASSERT_FALSE(elf->valid());
189
190 // Make sure this test is valid.
Christopher Ferrisbe788d82017-11-27 14:50:38 -0800191 delete info.elf;
Christopher Ferris5f118512017-09-01 11:17:16 -0700192 info.elf = nullptr;
193 info.end = 0x2000;
Christopher Ferrisbe788d82017-11-27 14:50:38 -0800194 elf = info.GetElf(process_memory_, false);
195 ASSERT_TRUE(elf != nullptr);
Christopher Ferris5f118512017-09-01 11:17:16 -0700196 ASSERT_TRUE(elf->valid());
197}
198
199// Verify that if the offset is non-zero but there is no elf at the offset,
200// that the full file is used.
201TEST_F(MapInfoGetElfTest, file_backed_non_zero_offset_full_file) {
Christopher Ferrisbe788d82017-11-27 14:50:38 -0800202 MapInfo info(0x1000, 0x2000, 0x100, PROT_READ, elf_.path);
Christopher Ferris5f118512017-09-01 11:17:16 -0700203
204 std::vector<uint8_t> buffer(0x1000);
205 memset(buffer.data(), 0, buffer.size());
206 Elf32_Ehdr ehdr;
207 TestInitEhdr<Elf32_Ehdr>(&ehdr, ELFCLASS32, EM_ARM);
208 memcpy(buffer.data(), &ehdr, sizeof(ehdr));
209 ASSERT_TRUE(android::base::WriteFully(elf_.fd, buffer.data(), buffer.size()));
210
Christopher Ferrisbe788d82017-11-27 14:50:38 -0800211 Elf* elf = info.GetElf(process_memory_, false);
212 ASSERT_TRUE(elf != nullptr);
Christopher Ferris5f118512017-09-01 11:17:16 -0700213 ASSERT_TRUE(elf->valid());
214 ASSERT_TRUE(elf->memory() != nullptr);
215 ASSERT_EQ(0x100U, info.elf_offset);
216
217 // Read the entire file.
218 memset(buffer.data(), 0, buffer.size());
219 ASSERT_TRUE(elf->memory()->Read(0, buffer.data(), buffer.size()));
220 ASSERT_EQ(0, memcmp(buffer.data(), &ehdr, sizeof(ehdr)));
221 for (size_t i = sizeof(ehdr); i < buffer.size(); i++) {
222 ASSERT_EQ(0, buffer[i]) << "Failed at byte " << i;
223 }
224
225 ASSERT_FALSE(elf->memory()->Read(buffer.size(), buffer.data(), 1));
226}
227
228// Verify that if the offset is non-zero and there is an elf at that
229// offset, that only part of the file is used.
230TEST_F(MapInfoGetElfTest, file_backed_non_zero_offset_partial_file) {
Christopher Ferrisbe788d82017-11-27 14:50:38 -0800231 MapInfo info(0x1000, 0x2000, 0x2000, PROT_READ, elf_.path);
Christopher Ferris5f118512017-09-01 11:17:16 -0700232
233 std::vector<uint8_t> buffer(0x4000);
234 memset(buffer.data(), 0, buffer.size());
235 Elf32_Ehdr ehdr;
236 TestInitEhdr<Elf32_Ehdr>(&ehdr, ELFCLASS32, EM_ARM);
237 memcpy(&buffer[info.offset], &ehdr, sizeof(ehdr));
238 ASSERT_TRUE(android::base::WriteFully(elf_.fd, buffer.data(), buffer.size()));
239
Christopher Ferrisbe788d82017-11-27 14:50:38 -0800240 Elf* elf = info.GetElf(process_memory_, false);
241 ASSERT_TRUE(elf != nullptr);
Christopher Ferris5f118512017-09-01 11:17:16 -0700242 ASSERT_TRUE(elf->valid());
243 ASSERT_TRUE(elf->memory() != nullptr);
244 ASSERT_EQ(0U, info.elf_offset);
245
246 // Read the valid part of the file.
247 ASSERT_TRUE(elf->memory()->Read(0, buffer.data(), 0x1000));
248 ASSERT_EQ(0, memcmp(buffer.data(), &ehdr, sizeof(ehdr)));
249 for (size_t i = sizeof(ehdr); i < 0x1000; i++) {
250 ASSERT_EQ(0, buffer[i]) << "Failed at byte " << i;
251 }
252
253 ASSERT_FALSE(elf->memory()->Read(0x1000, buffer.data(), 1));
254}
255
256// Verify that if the offset is non-zero and there is an elf at that
257// offset, that only part of the file is used. Further verify that if the
258// embedded elf is bigger than the initial map, the new object is larger
259// than the original map size. Do this for a 32 bit elf and a 64 bit elf.
260TEST_F(MapInfoGetElfTest, file_backed_non_zero_offset_partial_file_whole_elf32) {
Christopher Ferrisbe788d82017-11-27 14:50:38 -0800261 MapInfo info(0x5000, 0x6000, 0x1000, PROT_READ, elf_.path);
Christopher Ferris5f118512017-09-01 11:17:16 -0700262
263 std::vector<uint8_t> buffer(0x4000);
264 memset(buffer.data(), 0, buffer.size());
265 Elf32_Ehdr ehdr;
266 TestInitEhdr<Elf32_Ehdr>(&ehdr, ELFCLASS32, EM_ARM);
267 ehdr.e_shoff = 0x2000;
268 ehdr.e_shentsize = sizeof(Elf32_Shdr) + 100;
269 ehdr.e_shnum = 4;
270 memcpy(&buffer[info.offset], &ehdr, sizeof(ehdr));
271 ASSERT_TRUE(android::base::WriteFully(elf_.fd, buffer.data(), buffer.size()));
272
Christopher Ferrisbe788d82017-11-27 14:50:38 -0800273 Elf* elf = info.GetElf(process_memory_, false);
274 ASSERT_TRUE(elf != nullptr);
Christopher Ferris5f118512017-09-01 11:17:16 -0700275 ASSERT_TRUE(elf->valid());
276 ASSERT_TRUE(elf->memory() != nullptr);
277 ASSERT_EQ(0U, info.elf_offset);
278
279 // Verify the memory is a valid elf.
280 memset(buffer.data(), 0, buffer.size());
281 ASSERT_TRUE(elf->memory()->Read(0, buffer.data(), 0x1000));
282 ASSERT_EQ(0, memcmp(buffer.data(), &ehdr, sizeof(ehdr)));
283
284 // Read past the end of what would normally be the size of the map.
285 ASSERT_TRUE(elf->memory()->Read(0x1000, buffer.data(), 1));
286}
287
288TEST_F(MapInfoGetElfTest, file_backed_non_zero_offset_partial_file_whole_elf64) {
Christopher Ferrisbe788d82017-11-27 14:50:38 -0800289 MapInfo info(0x7000, 0x8000, 0x1000, PROT_READ, elf_.path);
Christopher Ferris5f118512017-09-01 11:17:16 -0700290
291 std::vector<uint8_t> buffer(0x4000);
292 memset(buffer.data(), 0, buffer.size());
293 Elf64_Ehdr ehdr;
294 TestInitEhdr<Elf64_Ehdr>(&ehdr, ELFCLASS64, EM_AARCH64);
295 ehdr.e_shoff = 0x2000;
296 ehdr.e_shentsize = sizeof(Elf64_Shdr) + 100;
297 ehdr.e_shnum = 4;
298 memcpy(&buffer[info.offset], &ehdr, sizeof(ehdr));
299 ASSERT_TRUE(android::base::WriteFully(elf_.fd, buffer.data(), buffer.size()));
300
Christopher Ferrisbe788d82017-11-27 14:50:38 -0800301 Elf* elf = info.GetElf(process_memory_, false);
302 ASSERT_TRUE(elf != nullptr);
Christopher Ferris5f118512017-09-01 11:17:16 -0700303 ASSERT_TRUE(elf->valid());
304 ASSERT_TRUE(elf->memory() != nullptr);
305 ASSERT_EQ(0U, info.elf_offset);
306
307 // Verify the memory is a valid elf.
308 memset(buffer.data(), 0, buffer.size());
309 ASSERT_TRUE(elf->memory()->Read(0, buffer.data(), 0x1000));
310 ASSERT_EQ(0, memcmp(buffer.data(), &ehdr, sizeof(ehdr)));
311
312 // Read past the end of what would normally be the size of the map.
313 ASSERT_TRUE(elf->memory()->Read(0x1000, buffer.data(), 1));
314}
315
316TEST_F(MapInfoGetElfTest, process_memory_not_read_only) {
Christopher Ferrisbe788d82017-11-27 14:50:38 -0800317 MapInfo info(0x9000, 0xa000, 0x1000, 0, "");
Christopher Ferris5f118512017-09-01 11:17:16 -0700318
319 // Create valid elf data in process memory only.
320 Elf64_Ehdr ehdr;
321 TestInitEhdr<Elf64_Ehdr>(&ehdr, ELFCLASS64, EM_AARCH64);
322 ehdr.e_shoff = 0x2000;
323 ehdr.e_shentsize = sizeof(Elf64_Shdr) + 100;
324 ehdr.e_shnum = 4;
325 memory_->SetMemory(0x9000, &ehdr, sizeof(ehdr));
326
Christopher Ferrisbe788d82017-11-27 14:50:38 -0800327 Elf* elf = info.GetElf(process_memory_, false);
328 ASSERT_TRUE(elf != nullptr);
Christopher Ferris5f118512017-09-01 11:17:16 -0700329 ASSERT_FALSE(elf->valid());
330
Christopher Ferrisbe788d82017-11-27 14:50:38 -0800331 delete info.elf;
Christopher Ferris5f118512017-09-01 11:17:16 -0700332 info.elf = nullptr;
333 info.flags = PROT_READ;
Christopher Ferrisbe788d82017-11-27 14:50:38 -0800334 elf = info.GetElf(process_memory_, false);
Christopher Ferris5f118512017-09-01 11:17:16 -0700335 ASSERT_TRUE(elf->valid());
336}
337
338TEST_F(MapInfoGetElfTest, check_device_maps) {
Christopher Ferrisbe788d82017-11-27 14:50:38 -0800339 MapInfo info(0x7000, 0x8000, 0x1000, PROT_READ | MAPS_FLAGS_DEVICE_MAP, "/dev/something");
Christopher Ferris5f118512017-09-01 11:17:16 -0700340
341 // Create valid elf data in process memory for this to verify that only
342 // the name is causing invalid elf data.
343 Elf64_Ehdr ehdr;
344 TestInitEhdr<Elf64_Ehdr>(&ehdr, ELFCLASS64, EM_X86_64);
345 ehdr.e_shoff = 0x2000;
346 ehdr.e_shentsize = sizeof(Elf64_Shdr) + 100;
347 ehdr.e_shnum = 4;
348 memory_->SetMemory(0x7000, &ehdr, sizeof(ehdr));
349
Christopher Ferrisbe788d82017-11-27 14:50:38 -0800350 Elf* elf = info.GetElf(process_memory_, false);
351 ASSERT_TRUE(elf != nullptr);
Christopher Ferris5f118512017-09-01 11:17:16 -0700352 ASSERT_FALSE(elf->valid());
353
354 // Set the name to nothing to verify that it still fails.
Christopher Ferrisbe788d82017-11-27 14:50:38 -0800355 delete info.elf;
Christopher Ferris5f118512017-09-01 11:17:16 -0700356 info.elf = nullptr;
357 info.name = "";
Christopher Ferrisbe788d82017-11-27 14:50:38 -0800358 elf = info.GetElf(process_memory_, false);
Christopher Ferris5f118512017-09-01 11:17:16 -0700359 ASSERT_FALSE(elf->valid());
360
361 // Change the flags and verify the elf is valid now.
Christopher Ferrisbe788d82017-11-27 14:50:38 -0800362 delete info.elf;
Christopher Ferris5f118512017-09-01 11:17:16 -0700363 info.elf = nullptr;
364 info.flags = PROT_READ;
Christopher Ferrisbe788d82017-11-27 14:50:38 -0800365 elf = info.GetElf(process_memory_, false);
Christopher Ferris5f118512017-09-01 11:17:16 -0700366 ASSERT_TRUE(elf->valid());
367}
368
Christopher Ferrisbe788d82017-11-27 14:50:38 -0800369TEST_F(MapInfoGetElfTest, multiple_thread_get_elf) {
370 static constexpr size_t kNumConcurrentThreads = 100;
371
372 Elf64_Ehdr ehdr;
373 TestInitEhdr<Elf64_Ehdr>(&ehdr, ELFCLASS64, EM_X86_64);
374 ehdr.e_shoff = 0x2000;
375 ehdr.e_shentsize = sizeof(Elf64_Shdr) + 100;
376 ehdr.e_shnum = 4;
377 memory_->SetMemory(0x7000, &ehdr, sizeof(ehdr));
378
379 Elf* elf_in_threads[kNumConcurrentThreads];
380 std::vector<std::thread*> threads;
381
382 std::atomic_bool wait;
383 wait = true;
384 // Create all of the threads and have them do the GetElf at the same time
385 // to make it likely that a race will occur.
386 MapInfo info(0x7000, 0x8000, 0x1000, PROT_READ, "");
387 for (size_t i = 0; i < kNumConcurrentThreads; i++) {
388 std::thread* thread = new std::thread([i, this, &wait, &info, &elf_in_threads]() {
389 while (wait)
390 ;
391 Elf* elf = info.GetElf(process_memory_, false);
392 elf_in_threads[i] = elf;
393 });
394 threads.push_back(thread);
395 }
396 ASSERT_TRUE(info.elf == nullptr);
397
398 // Set them all going and wait for the threads to finish.
399 wait = false;
400 for (auto thread : threads) {
401 thread->join();
402 delete thread;
403 }
404
405 // Now verify that all of the elf files are exactly the same and valid.
406 Elf* elf = info.elf;
407 ASSERT_TRUE(elf != nullptr);
408 EXPECT_TRUE(elf->valid());
409 for (size_t i = 0; i < kNumConcurrentThreads; i++) {
410 EXPECT_EQ(elf, elf_in_threads[i]) << "Thread " << i << " mismatched.";
411 }
412}
413
Christopher Ferrisd226a512017-07-14 10:37:19 -0700414} // namespace unwindstack