blob: 4d74696907b0043008fe893186bbc95f66611195 [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 Ferris9d5712c2018-10-01 21:01:09 -070072 MapInfo info(nullptr, 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 Ferris4568f4b2018-10-23 17:42:41 -070075 Elf* elf = info.GetElf(process_memory_, ARCH_ARM);
Christopher Ferrisbe788d82017-11-27 14:50:38 -080076 ASSERT_TRUE(elf != nullptr);
Christopher Ferris570b76f2017-06-30 17:18:16 -070077 ASSERT_FALSE(elf->valid());
78}
79
80TEST_F(MapInfoGetElfTest, valid32) {
Christopher Ferris9d5712c2018-10-01 21:01:09 -070081 MapInfo info(nullptr, 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 Ferris4568f4b2018-10-23 17:42:41 -070087 Elf* elf = info.GetElf(process_memory_, ARCH_ARM);
Christopher Ferrisbe788d82017-11-27 14:50:38 -080088 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 Ferris9d5712c2018-10-01 21:01:09 -070095 MapInfo info(nullptr, 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 Ferris4568f4b2018-10-23 17:42:41 -0700101 Elf* elf = info.GetElf(process_memory_, ARCH_ARM64);
Christopher Ferrisbe788d82017-11-27 14:50:38 -0800102 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
Christopher Ferris4568f4b2018-10-23 17:42:41 -0700108TEST_F(MapInfoGetElfTest, invalid_arch_mismatch) {
109 MapInfo info(nullptr, 0x3000, 0x4000, 0, PROT_READ, "");
110
111 Elf32_Ehdr ehdr;
112 TestInitEhdr<Elf32_Ehdr>(&ehdr, ELFCLASS32, EM_ARM);
113 memory_->SetMemory(0x3000, &ehdr, sizeof(ehdr));
114
115 Elf* elf = info.GetElf(process_memory_, ARCH_X86);
116 ASSERT_TRUE(elf != nullptr);
117 ASSERT_FALSE(elf->valid());
118}
119
Christopher Ferris570b76f2017-06-30 17:18:16 -0700120TEST_F(MapInfoGetElfTest, gnu_debugdata_init32) {
Christopher Ferris9d5712c2018-10-01 21:01:09 -0700121 MapInfo info(nullptr, 0x2000, 0x3000, 0, PROT_READ, "");
Christopher Ferris570b76f2017-06-30 17:18:16 -0700122
Christopher Ferris5f118512017-09-01 11:17:16 -0700123 TestInitGnuDebugdata<Elf32_Ehdr, Elf32_Shdr>(ELFCLASS32, EM_ARM, true,
124 [&](uint64_t offset, const void* ptr, size_t size) {
125 memory_->SetMemory(0x2000 + offset, ptr, size);
126 });
127
Christopher Ferris4568f4b2018-10-23 17:42:41 -0700128 Elf* elf = info.GetElf(process_memory_, ARCH_ARM);
Christopher Ferrisbe788d82017-11-27 14:50:38 -0800129 ASSERT_TRUE(elf != nullptr);
Christopher Ferris570b76f2017-06-30 17:18:16 -0700130 ASSERT_TRUE(elf->valid());
131 EXPECT_EQ(static_cast<uint32_t>(EM_ARM), elf->machine_type());
132 EXPECT_EQ(ELFCLASS32, elf->class_type());
133 EXPECT_TRUE(elf->gnu_debugdata_interface() != nullptr);
134}
135
136TEST_F(MapInfoGetElfTest, gnu_debugdata_init64) {
Christopher Ferris9d5712c2018-10-01 21:01:09 -0700137 MapInfo info(nullptr, 0x5000, 0x8000, 0, PROT_READ, "");
Christopher Ferris570b76f2017-06-30 17:18:16 -0700138
Christopher Ferris5f118512017-09-01 11:17:16 -0700139 TestInitGnuDebugdata<Elf64_Ehdr, Elf64_Shdr>(ELFCLASS64, EM_AARCH64, true,
140 [&](uint64_t offset, const void* ptr, size_t size) {
141 memory_->SetMemory(0x5000 + offset, ptr, size);
142 });
143
Christopher Ferris4568f4b2018-10-23 17:42:41 -0700144 Elf* elf = info.GetElf(process_memory_, ARCH_ARM64);
Christopher Ferrisbe788d82017-11-27 14:50:38 -0800145 ASSERT_TRUE(elf != nullptr);
Christopher Ferris570b76f2017-06-30 17:18:16 -0700146 ASSERT_TRUE(elf->valid());
147 EXPECT_EQ(static_cast<uint32_t>(EM_AARCH64), elf->machine_type());
148 EXPECT_EQ(ELFCLASS64, elf->class_type());
149 EXPECT_TRUE(elf->gnu_debugdata_interface() != nullptr);
150}
Christopher Ferrisd226a512017-07-14 10:37:19 -0700151
Christopher Ferris5f118512017-09-01 11:17:16 -0700152TEST_F(MapInfoGetElfTest, end_le_start) {
Christopher Ferris9d5712c2018-10-01 21:01:09 -0700153 MapInfo info(nullptr, 0x1000, 0x1000, 0, PROT_READ, elf_.path);
Christopher Ferris5f118512017-09-01 11:17:16 -0700154
155 Elf32_Ehdr ehdr;
156 TestInitEhdr<Elf32_Ehdr>(&ehdr, ELFCLASS32, EM_ARM);
157 ASSERT_TRUE(android::base::WriteFully(elf_.fd, &ehdr, sizeof(ehdr)));
158
Christopher Ferris4568f4b2018-10-23 17:42:41 -0700159 Elf* elf = info.GetElf(process_memory_, ARCH_ARM);
Christopher Ferrisbe788d82017-11-27 14:50:38 -0800160 ASSERT_TRUE(elf != nullptr);
Christopher Ferris5f118512017-09-01 11:17:16 -0700161 ASSERT_FALSE(elf->valid());
162
Christopher Ferris0b79ae12018-01-25 12:15:56 -0800163 info.elf.reset();
Christopher Ferris5f118512017-09-01 11:17:16 -0700164 info.end = 0xfff;
Christopher Ferris4568f4b2018-10-23 17:42:41 -0700165 elf = info.GetElf(process_memory_, ARCH_ARM);
Christopher Ferrisbe788d82017-11-27 14:50:38 -0800166 ASSERT_TRUE(elf != nullptr);
Christopher Ferris5f118512017-09-01 11:17:16 -0700167 ASSERT_FALSE(elf->valid());
168
169 // Make sure this test is valid.
Christopher Ferris0b79ae12018-01-25 12:15:56 -0800170 info.elf.reset();
Christopher Ferris5f118512017-09-01 11:17:16 -0700171 info.end = 0x2000;
Christopher Ferris4568f4b2018-10-23 17:42:41 -0700172 elf = info.GetElf(process_memory_, ARCH_ARM);
Christopher Ferrisbe788d82017-11-27 14:50:38 -0800173 ASSERT_TRUE(elf != nullptr);
Christopher Ferris5f118512017-09-01 11:17:16 -0700174 ASSERT_TRUE(elf->valid());
175}
176
177// Verify that if the offset is non-zero but there is no elf at the offset,
178// that the full file is used.
179TEST_F(MapInfoGetElfTest, file_backed_non_zero_offset_full_file) {
Christopher Ferris9d5712c2018-10-01 21:01:09 -0700180 MapInfo info(nullptr, 0x1000, 0x2000, 0x100, PROT_READ, elf_.path);
Christopher Ferris5f118512017-09-01 11:17:16 -0700181
182 std::vector<uint8_t> buffer(0x1000);
183 memset(buffer.data(), 0, buffer.size());
184 Elf32_Ehdr ehdr;
185 TestInitEhdr<Elf32_Ehdr>(&ehdr, ELFCLASS32, EM_ARM);
186 memcpy(buffer.data(), &ehdr, sizeof(ehdr));
187 ASSERT_TRUE(android::base::WriteFully(elf_.fd, buffer.data(), buffer.size()));
188
Christopher Ferris4568f4b2018-10-23 17:42:41 -0700189 Elf* elf = info.GetElf(process_memory_, ARCH_ARM);
Christopher Ferrisbe788d82017-11-27 14:50:38 -0800190 ASSERT_TRUE(elf != nullptr);
Christopher Ferris5f118512017-09-01 11:17:16 -0700191 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());
Josh Gaoef35aa52017-10-18 11:44:51 -0700197 ASSERT_TRUE(elf->memory()->ReadFully(0, buffer.data(), buffer.size()));
Christopher Ferris5f118512017-09-01 11:17:16 -0700198 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
Josh Gaoef35aa52017-10-18 11:44:51 -0700203 ASSERT_FALSE(elf->memory()->ReadFully(buffer.size(), buffer.data(), 1));
Christopher Ferris5f118512017-09-01 11:17:16 -0700204}
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.
208TEST_F(MapInfoGetElfTest, file_backed_non_zero_offset_partial_file) {
Christopher Ferris9d5712c2018-10-01 21:01:09 -0700209 MapInfo info(nullptr, 0x1000, 0x2000, 0x2000, PROT_READ, elf_.path);
Christopher Ferris5f118512017-09-01 11:17:16 -0700210
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
Christopher Ferris4568f4b2018-10-23 17:42:41 -0700218 Elf* elf = info.GetElf(process_memory_, ARCH_ARM);
Christopher Ferrisbe788d82017-11-27 14:50:38 -0800219 ASSERT_TRUE(elf != nullptr);
Christopher Ferris5f118512017-09-01 11:17:16 -0700220 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.
Josh Gaoef35aa52017-10-18 11:44:51 -0700225 ASSERT_TRUE(elf->memory()->ReadFully(0, buffer.data(), 0x1000));
Christopher Ferris5f118512017-09-01 11:17:16 -0700226 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
Josh Gaoef35aa52017-10-18 11:44:51 -0700231 ASSERT_FALSE(elf->memory()->ReadFully(0x1000, buffer.data(), 1));
Christopher Ferris5f118512017-09-01 11:17:16 -0700232}
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.
238TEST_F(MapInfoGetElfTest, file_backed_non_zero_offset_partial_file_whole_elf32) {
Christopher Ferris9d5712c2018-10-01 21:01:09 -0700239 MapInfo info(nullptr, 0x5000, 0x6000, 0x1000, PROT_READ, elf_.path);
Christopher Ferris5f118512017-09-01 11:17:16 -0700240
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
Christopher Ferris4568f4b2018-10-23 17:42:41 -0700251 Elf* elf = info.GetElf(process_memory_, ARCH_ARM);
Christopher Ferrisbe788d82017-11-27 14:50:38 -0800252 ASSERT_TRUE(elf != nullptr);
Christopher Ferris5f118512017-09-01 11:17:16 -0700253 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());
Josh Gaoef35aa52017-10-18 11:44:51 -0700259 ASSERT_TRUE(elf->memory()->ReadFully(0, buffer.data(), 0x1000));
Christopher Ferris5f118512017-09-01 11:17:16 -0700260 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.
Josh Gaoef35aa52017-10-18 11:44:51 -0700263 ASSERT_TRUE(elf->memory()->ReadFully(0x1000, buffer.data(), 1));
Christopher Ferris5f118512017-09-01 11:17:16 -0700264}
265
266TEST_F(MapInfoGetElfTest, file_backed_non_zero_offset_partial_file_whole_elf64) {
Christopher Ferris9d5712c2018-10-01 21:01:09 -0700267 MapInfo info(nullptr, 0x7000, 0x8000, 0x1000, PROT_READ, elf_.path);
Christopher Ferris5f118512017-09-01 11:17:16 -0700268
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
Christopher Ferris4568f4b2018-10-23 17:42:41 -0700279 Elf* elf = info.GetElf(process_memory_, ARCH_ARM64);
Christopher Ferrisbe788d82017-11-27 14:50:38 -0800280 ASSERT_TRUE(elf != nullptr);
Christopher Ferris5f118512017-09-01 11:17:16 -0700281 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());
Josh Gaoef35aa52017-10-18 11:44:51 -0700287 ASSERT_TRUE(elf->memory()->ReadFully(0, buffer.data(), 0x1000));
Christopher Ferris5f118512017-09-01 11:17:16 -0700288 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.
Josh Gaoef35aa52017-10-18 11:44:51 -0700291 ASSERT_TRUE(elf->memory()->ReadFully(0x1000, buffer.data(), 1));
Christopher Ferris5f118512017-09-01 11:17:16 -0700292}
293
294TEST_F(MapInfoGetElfTest, process_memory_not_read_only) {
Christopher Ferris9d5712c2018-10-01 21:01:09 -0700295 MapInfo info(nullptr, 0x9000, 0xa000, 0x1000, 0, "");
Christopher Ferris5f118512017-09-01 11:17:16 -0700296
297 // Create valid elf data in process memory only.
298 Elf64_Ehdr ehdr;
299 TestInitEhdr<Elf64_Ehdr>(&ehdr, ELFCLASS64, EM_AARCH64);
300 ehdr.e_shoff = 0x2000;
301 ehdr.e_shentsize = sizeof(Elf64_Shdr) + 100;
Christopher Ferris5acf0692018-08-01 13:10:46 -0700302 ehdr.e_shnum = 0;
Christopher Ferris5f118512017-09-01 11:17:16 -0700303 memory_->SetMemory(0x9000, &ehdr, sizeof(ehdr));
304
Christopher Ferris4568f4b2018-10-23 17:42:41 -0700305 Elf* elf = info.GetElf(process_memory_, ARCH_ARM64);
Christopher Ferrisbe788d82017-11-27 14:50:38 -0800306 ASSERT_TRUE(elf != nullptr);
Christopher Ferris5f118512017-09-01 11:17:16 -0700307 ASSERT_FALSE(elf->valid());
308
Christopher Ferris0b79ae12018-01-25 12:15:56 -0800309 info.elf.reset();
Christopher Ferris5f118512017-09-01 11:17:16 -0700310 info.flags = PROT_READ;
Christopher Ferris4568f4b2018-10-23 17:42:41 -0700311 elf = info.GetElf(process_memory_, ARCH_ARM64);
Christopher Ferris5f118512017-09-01 11:17:16 -0700312 ASSERT_TRUE(elf->valid());
313}
314
315TEST_F(MapInfoGetElfTest, check_device_maps) {
Christopher Ferris9d5712c2018-10-01 21:01:09 -0700316 MapInfo info(nullptr, 0x7000, 0x8000, 0x1000, PROT_READ | MAPS_FLAGS_DEVICE_MAP,
317 "/dev/something");
Christopher Ferris5f118512017-09-01 11:17:16 -0700318
319 // Create valid elf data in process memory for this to verify that only
320 // the name is causing invalid elf data.
321 Elf64_Ehdr ehdr;
322 TestInitEhdr<Elf64_Ehdr>(&ehdr, ELFCLASS64, EM_X86_64);
323 ehdr.e_shoff = 0x2000;
324 ehdr.e_shentsize = sizeof(Elf64_Shdr) + 100;
Christopher Ferris5acf0692018-08-01 13:10:46 -0700325 ehdr.e_shnum = 0;
Christopher Ferris5f118512017-09-01 11:17:16 -0700326 memory_->SetMemory(0x7000, &ehdr, sizeof(ehdr));
327
Christopher Ferris4568f4b2018-10-23 17:42:41 -0700328 Elf* elf = info.GetElf(process_memory_, ARCH_X86_64);
Christopher Ferrisbe788d82017-11-27 14:50:38 -0800329 ASSERT_TRUE(elf != nullptr);
Christopher Ferris5f118512017-09-01 11:17:16 -0700330 ASSERT_FALSE(elf->valid());
331
332 // Set the name to nothing to verify that it still fails.
Christopher Ferris0b79ae12018-01-25 12:15:56 -0800333 info.elf.reset();
Christopher Ferris5f118512017-09-01 11:17:16 -0700334 info.name = "";
Christopher Ferris4568f4b2018-10-23 17:42:41 -0700335 elf = info.GetElf(process_memory_, ARCH_X86_64);
Christopher Ferris5f118512017-09-01 11:17:16 -0700336 ASSERT_FALSE(elf->valid());
337
338 // Change the flags and verify the elf is valid now.
Christopher Ferris0b79ae12018-01-25 12:15:56 -0800339 info.elf.reset();
Christopher Ferris5f118512017-09-01 11:17:16 -0700340 info.flags = PROT_READ;
Christopher Ferris4568f4b2018-10-23 17:42:41 -0700341 elf = info.GetElf(process_memory_, ARCH_X86_64);
Christopher Ferris5f118512017-09-01 11:17:16 -0700342 ASSERT_TRUE(elf->valid());
343}
344
Christopher Ferrisbe788d82017-11-27 14:50:38 -0800345TEST_F(MapInfoGetElfTest, multiple_thread_get_elf) {
346 static constexpr size_t kNumConcurrentThreads = 100;
347
348 Elf64_Ehdr ehdr;
349 TestInitEhdr<Elf64_Ehdr>(&ehdr, ELFCLASS64, EM_X86_64);
350 ehdr.e_shoff = 0x2000;
351 ehdr.e_shentsize = sizeof(Elf64_Shdr) + 100;
Christopher Ferris5acf0692018-08-01 13:10:46 -0700352 ehdr.e_shnum = 0;
Christopher Ferrisbe788d82017-11-27 14:50:38 -0800353 memory_->SetMemory(0x7000, &ehdr, sizeof(ehdr));
354
355 Elf* elf_in_threads[kNumConcurrentThreads];
356 std::vector<std::thread*> threads;
357
358 std::atomic_bool wait;
359 wait = true;
360 // Create all of the threads and have them do the GetElf at the same time
361 // to make it likely that a race will occur.
Christopher Ferris9d5712c2018-10-01 21:01:09 -0700362 MapInfo info(nullptr, 0x7000, 0x8000, 0x1000, PROT_READ, "");
Christopher Ferrisbe788d82017-11-27 14:50:38 -0800363 for (size_t i = 0; i < kNumConcurrentThreads; i++) {
364 std::thread* thread = new std::thread([i, this, &wait, &info, &elf_in_threads]() {
365 while (wait)
366 ;
Christopher Ferris4568f4b2018-10-23 17:42:41 -0700367 Elf* elf = info.GetElf(process_memory_, ARCH_X86_64);
Christopher Ferrisbe788d82017-11-27 14:50:38 -0800368 elf_in_threads[i] = elf;
369 });
370 threads.push_back(thread);
371 }
372 ASSERT_TRUE(info.elf == nullptr);
373
374 // Set them all going and wait for the threads to finish.
375 wait = false;
376 for (auto thread : threads) {
377 thread->join();
378 delete thread;
379 }
380
381 // Now verify that all of the elf files are exactly the same and valid.
Christopher Ferris0b79ae12018-01-25 12:15:56 -0800382 Elf* elf = info.elf.get();
Christopher Ferrisbe788d82017-11-27 14:50:38 -0800383 ASSERT_TRUE(elf != nullptr);
384 EXPECT_TRUE(elf->valid());
385 for (size_t i = 0; i < kNumConcurrentThreads; i++) {
386 EXPECT_EQ(elf, elf_in_threads[i]) << "Thread " << i << " mismatched.";
387 }
388}
389
Christopher Ferrisd226a512017-07-14 10:37:19 -0700390} // namespace unwindstack