blob: f3b4679558c58de81f28fa5f1824f9dda224c4b8 [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>
Christopher Ferris570b76f2017-06-30 17:18:16 -070032#include <gtest/gtest.h>
33
Christopher Ferrisd226a512017-07-14 10:37:19 -070034#include <unwindstack/Elf.h>
35#include <unwindstack/MapInfo.h>
Christopher Ferris5f118512017-09-01 11:17:16 -070036#include <unwindstack/Maps.h>
Christopher Ferrisd226a512017-07-14 10:37:19 -070037#include <unwindstack/Memory.h>
38
Christopher Ferris570b76f2017-06-30 17:18:16 -070039#include "ElfTestUtils.h"
Christopher Ferris5f118512017-09-01 11:17:16 -070040#include "MemoryFake.h"
Christopher Ferrisd226a512017-07-14 10:37:19 -070041
42namespace unwindstack {
Christopher Ferris570b76f2017-06-30 17:18:16 -070043
44class MapInfoGetElfTest : public ::testing::Test {
45 protected:
46 void SetUp() override {
Christopher Ferris5f118512017-09-01 11:17:16 -070047 memory_ = new MemoryFake;
48 process_memory_.reset(memory_);
Christopher Ferris570b76f2017-06-30 17:18:16 -070049 }
50
Christopher Ferris5f118512017-09-01 11:17:16 -070051 template <typename Ehdr, typename Shdr>
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 }
Christopher Ferris570b76f2017-06-30 17:18:16 -070061
62 const size_t kMapSize = 4096;
63
Christopher Ferris5f118512017-09-01 11:17:16 -070064 std::shared_ptr<Memory> process_memory_;
65 MemoryFake* memory_;
66
67 TemporaryFile elf_;
Christopher Ferris570b76f2017-06-30 17:18:16 -070068};
69
70TEST_F(MapInfoGetElfTest, invalid) {
Christopher Ferris9d5712c2018-10-01 21:01:09 -070071 MapInfo info(nullptr, 0x1000, 0x2000, 0, PROT_READ, "");
Christopher Ferris5f118512017-09-01 11:17:16 -070072
Christopher Ferris570b76f2017-06-30 17:18:16 -070073 // The map is empty, but this should still create an invalid elf object.
Christopher Ferris4568f4b2018-10-23 17:42:41 -070074 Elf* elf = info.GetElf(process_memory_, ARCH_ARM);
Christopher Ferrisbe788d82017-11-27 14:50:38 -080075 ASSERT_TRUE(elf != nullptr);
Christopher Ferris570b76f2017-06-30 17:18:16 -070076 ASSERT_FALSE(elf->valid());
77}
78
79TEST_F(MapInfoGetElfTest, valid32) {
Christopher Ferris9d5712c2018-10-01 21:01:09 -070080 MapInfo info(nullptr, 0x3000, 0x4000, 0, PROT_READ, "");
Christopher Ferris5f118512017-09-01 11:17:16 -070081
Christopher Ferris570b76f2017-06-30 17:18:16 -070082 Elf32_Ehdr ehdr;
83 TestInitEhdr<Elf32_Ehdr>(&ehdr, ELFCLASS32, EM_ARM);
Christopher Ferris5f118512017-09-01 11:17:16 -070084 memory_->SetMemory(0x3000, &ehdr, sizeof(ehdr));
Christopher Ferris570b76f2017-06-30 17:18:16 -070085
Christopher Ferris4568f4b2018-10-23 17:42:41 -070086 Elf* elf = info.GetElf(process_memory_, ARCH_ARM);
Christopher Ferrisbe788d82017-11-27 14:50:38 -080087 ASSERT_TRUE(elf != nullptr);
Christopher Ferris570b76f2017-06-30 17:18:16 -070088 ASSERT_TRUE(elf->valid());
89 EXPECT_EQ(static_cast<uint32_t>(EM_ARM), elf->machine_type());
90 EXPECT_EQ(ELFCLASS32, elf->class_type());
91}
92
93TEST_F(MapInfoGetElfTest, valid64) {
Christopher Ferris9d5712c2018-10-01 21:01:09 -070094 MapInfo info(nullptr, 0x8000, 0x9000, 0, PROT_READ, "");
Christopher Ferris5f118512017-09-01 11:17:16 -070095
Christopher Ferris570b76f2017-06-30 17:18:16 -070096 Elf64_Ehdr ehdr;
97 TestInitEhdr<Elf64_Ehdr>(&ehdr, ELFCLASS64, EM_AARCH64);
Christopher Ferris5f118512017-09-01 11:17:16 -070098 memory_->SetMemory(0x8000, &ehdr, sizeof(ehdr));
Christopher Ferris570b76f2017-06-30 17:18:16 -070099
Christopher Ferris4568f4b2018-10-23 17:42:41 -0700100 Elf* elf = info.GetElf(process_memory_, ARCH_ARM64);
Christopher Ferrisbe788d82017-11-27 14:50:38 -0800101 ASSERT_TRUE(elf != nullptr);
Christopher Ferris570b76f2017-06-30 17:18:16 -0700102 ASSERT_TRUE(elf->valid());
103 EXPECT_EQ(static_cast<uint32_t>(EM_AARCH64), elf->machine_type());
104 EXPECT_EQ(ELFCLASS64, elf->class_type());
105}
106
Christopher Ferris4568f4b2018-10-23 17:42:41 -0700107TEST_F(MapInfoGetElfTest, invalid_arch_mismatch) {
108 MapInfo info(nullptr, 0x3000, 0x4000, 0, PROT_READ, "");
109
110 Elf32_Ehdr ehdr;
111 TestInitEhdr<Elf32_Ehdr>(&ehdr, ELFCLASS32, EM_ARM);
112 memory_->SetMemory(0x3000, &ehdr, sizeof(ehdr));
113
114 Elf* elf = info.GetElf(process_memory_, ARCH_X86);
115 ASSERT_TRUE(elf != nullptr);
116 ASSERT_FALSE(elf->valid());
117}
118
Christopher Ferris570b76f2017-06-30 17:18:16 -0700119TEST_F(MapInfoGetElfTest, gnu_debugdata_init32) {
Christopher Ferris9d5712c2018-10-01 21:01:09 -0700120 MapInfo info(nullptr, 0x2000, 0x3000, 0, PROT_READ, "");
Christopher Ferris570b76f2017-06-30 17:18:16 -0700121
Christopher Ferris5f118512017-09-01 11:17:16 -0700122 TestInitGnuDebugdata<Elf32_Ehdr, Elf32_Shdr>(ELFCLASS32, EM_ARM, true,
123 [&](uint64_t offset, const void* ptr, size_t size) {
124 memory_->SetMemory(0x2000 + offset, ptr, size);
125 });
126
Christopher Ferris4568f4b2018-10-23 17:42:41 -0700127 Elf* elf = info.GetElf(process_memory_, ARCH_ARM);
Christopher Ferrisbe788d82017-11-27 14:50:38 -0800128 ASSERT_TRUE(elf != nullptr);
Christopher Ferris570b76f2017-06-30 17:18:16 -0700129 ASSERT_TRUE(elf->valid());
130 EXPECT_EQ(static_cast<uint32_t>(EM_ARM), elf->machine_type());
131 EXPECT_EQ(ELFCLASS32, elf->class_type());
132 EXPECT_TRUE(elf->gnu_debugdata_interface() != nullptr);
133}
134
135TEST_F(MapInfoGetElfTest, gnu_debugdata_init64) {
Christopher Ferris9d5712c2018-10-01 21:01:09 -0700136 MapInfo info(nullptr, 0x5000, 0x8000, 0, PROT_READ, "");
Christopher Ferris570b76f2017-06-30 17:18:16 -0700137
Christopher Ferris5f118512017-09-01 11:17:16 -0700138 TestInitGnuDebugdata<Elf64_Ehdr, Elf64_Shdr>(ELFCLASS64, EM_AARCH64, true,
139 [&](uint64_t offset, const void* ptr, size_t size) {
140 memory_->SetMemory(0x5000 + offset, ptr, size);
141 });
142
Christopher Ferris4568f4b2018-10-23 17:42:41 -0700143 Elf* elf = info.GetElf(process_memory_, ARCH_ARM64);
Christopher Ferrisbe788d82017-11-27 14:50:38 -0800144 ASSERT_TRUE(elf != nullptr);
Christopher Ferris570b76f2017-06-30 17:18:16 -0700145 ASSERT_TRUE(elf->valid());
146 EXPECT_EQ(static_cast<uint32_t>(EM_AARCH64), elf->machine_type());
147 EXPECT_EQ(ELFCLASS64, elf->class_type());
148 EXPECT_TRUE(elf->gnu_debugdata_interface() != nullptr);
149}
Christopher Ferrisd226a512017-07-14 10:37:19 -0700150
Christopher Ferris5f118512017-09-01 11:17:16 -0700151TEST_F(MapInfoGetElfTest, end_le_start) {
Christopher Ferris9d5712c2018-10-01 21:01:09 -0700152 MapInfo info(nullptr, 0x1000, 0x1000, 0, PROT_READ, elf_.path);
Christopher Ferris5f118512017-09-01 11:17:16 -0700153
154 Elf32_Ehdr ehdr;
155 TestInitEhdr<Elf32_Ehdr>(&ehdr, ELFCLASS32, EM_ARM);
156 ASSERT_TRUE(android::base::WriteFully(elf_.fd, &ehdr, sizeof(ehdr)));
157
Christopher Ferris4568f4b2018-10-23 17:42:41 -0700158 Elf* elf = info.GetElf(process_memory_, ARCH_ARM);
Christopher Ferrisbe788d82017-11-27 14:50:38 -0800159 ASSERT_TRUE(elf != nullptr);
Christopher Ferris5f118512017-09-01 11:17:16 -0700160 ASSERT_FALSE(elf->valid());
161
Christopher Ferris0b79ae12018-01-25 12:15:56 -0800162 info.elf.reset();
Christopher Ferris5f118512017-09-01 11:17:16 -0700163 info.end = 0xfff;
Christopher Ferris4568f4b2018-10-23 17:42:41 -0700164 elf = info.GetElf(process_memory_, ARCH_ARM);
Christopher Ferrisbe788d82017-11-27 14:50:38 -0800165 ASSERT_TRUE(elf != nullptr);
Christopher Ferris5f118512017-09-01 11:17:16 -0700166 ASSERT_FALSE(elf->valid());
167
168 // Make sure this test is valid.
Christopher Ferris0b79ae12018-01-25 12:15:56 -0800169 info.elf.reset();
Christopher Ferris5f118512017-09-01 11:17:16 -0700170 info.end = 0x2000;
Christopher Ferris4568f4b2018-10-23 17:42:41 -0700171 elf = info.GetElf(process_memory_, ARCH_ARM);
Christopher Ferrisbe788d82017-11-27 14:50:38 -0800172 ASSERT_TRUE(elf != nullptr);
Christopher Ferris5f118512017-09-01 11:17:16 -0700173 ASSERT_TRUE(elf->valid());
174}
175
176// Verify that if the offset is non-zero but there is no elf at the offset,
177// that the full file is used.
178TEST_F(MapInfoGetElfTest, file_backed_non_zero_offset_full_file) {
Christopher Ferris9d5712c2018-10-01 21:01:09 -0700179 MapInfo info(nullptr, 0x1000, 0x2000, 0x100, PROT_READ, elf_.path);
Christopher Ferris5f118512017-09-01 11:17:16 -0700180
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
Christopher Ferris4568f4b2018-10-23 17:42:41 -0700188 Elf* elf = info.GetElf(process_memory_, ARCH_ARM);
Christopher Ferrisbe788d82017-11-27 14:50:38 -0800189 ASSERT_TRUE(elf != nullptr);
Christopher Ferris5f118512017-09-01 11:17:16 -0700190 ASSERT_TRUE(elf->valid());
191 ASSERT_TRUE(elf->memory() != nullptr);
192 ASSERT_EQ(0x100U, info.elf_offset);
193
194 // Read the entire file.
195 memset(buffer.data(), 0, buffer.size());
Josh Gaoef35aa52017-10-18 11:44:51 -0700196 ASSERT_TRUE(elf->memory()->ReadFully(0, buffer.data(), buffer.size()));
Christopher Ferris5f118512017-09-01 11:17:16 -0700197 ASSERT_EQ(0, memcmp(buffer.data(), &ehdr, sizeof(ehdr)));
198 for (size_t i = sizeof(ehdr); i < buffer.size(); i++) {
199 ASSERT_EQ(0, buffer[i]) << "Failed at byte " << i;
200 }
201
Josh Gaoef35aa52017-10-18 11:44:51 -0700202 ASSERT_FALSE(elf->memory()->ReadFully(buffer.size(), buffer.data(), 1));
Christopher Ferris5f118512017-09-01 11:17:16 -0700203}
204
205// Verify that if the offset is non-zero and there is an elf at that
206// offset, that only part of the file is used.
207TEST_F(MapInfoGetElfTest, file_backed_non_zero_offset_partial_file) {
Christopher Ferris9d5712c2018-10-01 21:01:09 -0700208 MapInfo info(nullptr, 0x1000, 0x2000, 0x2000, PROT_READ, elf_.path);
Christopher Ferris5f118512017-09-01 11:17:16 -0700209
210 std::vector<uint8_t> buffer(0x4000);
211 memset(buffer.data(), 0, buffer.size());
212 Elf32_Ehdr ehdr;
213 TestInitEhdr<Elf32_Ehdr>(&ehdr, ELFCLASS32, EM_ARM);
214 memcpy(&buffer[info.offset], &ehdr, sizeof(ehdr));
215 ASSERT_TRUE(android::base::WriteFully(elf_.fd, buffer.data(), buffer.size()));
216
Christopher Ferris4568f4b2018-10-23 17:42:41 -0700217 Elf* elf = info.GetElf(process_memory_, ARCH_ARM);
Christopher Ferrisbe788d82017-11-27 14:50:38 -0800218 ASSERT_TRUE(elf != nullptr);
Christopher Ferris5f118512017-09-01 11:17:16 -0700219 ASSERT_TRUE(elf->valid());
220 ASSERT_TRUE(elf->memory() != nullptr);
221 ASSERT_EQ(0U, info.elf_offset);
222
223 // Read the valid part of the file.
Josh Gaoef35aa52017-10-18 11:44:51 -0700224 ASSERT_TRUE(elf->memory()->ReadFully(0, buffer.data(), 0x1000));
Christopher Ferris5f118512017-09-01 11:17:16 -0700225 ASSERT_EQ(0, memcmp(buffer.data(), &ehdr, sizeof(ehdr)));
226 for (size_t i = sizeof(ehdr); i < 0x1000; i++) {
227 ASSERT_EQ(0, buffer[i]) << "Failed at byte " << i;
228 }
229
Josh Gaoef35aa52017-10-18 11:44:51 -0700230 ASSERT_FALSE(elf->memory()->ReadFully(0x1000, buffer.data(), 1));
Christopher Ferris5f118512017-09-01 11:17:16 -0700231}
232
233// Verify that if the offset is non-zero and there is an elf at that
234// offset, that only part of the file is used. Further verify that if the
235// embedded elf is bigger than the initial map, the new object is larger
236// than the original map size. Do this for a 32 bit elf and a 64 bit elf.
237TEST_F(MapInfoGetElfTest, file_backed_non_zero_offset_partial_file_whole_elf32) {
Christopher Ferris9d5712c2018-10-01 21:01:09 -0700238 MapInfo info(nullptr, 0x5000, 0x6000, 0x1000, PROT_READ, elf_.path);
Christopher Ferris5f118512017-09-01 11:17:16 -0700239
240 std::vector<uint8_t> buffer(0x4000);
241 memset(buffer.data(), 0, buffer.size());
242 Elf32_Ehdr ehdr;
243 TestInitEhdr<Elf32_Ehdr>(&ehdr, ELFCLASS32, EM_ARM);
244 ehdr.e_shoff = 0x2000;
245 ehdr.e_shentsize = sizeof(Elf32_Shdr) + 100;
246 ehdr.e_shnum = 4;
247 memcpy(&buffer[info.offset], &ehdr, sizeof(ehdr));
248 ASSERT_TRUE(android::base::WriteFully(elf_.fd, buffer.data(), buffer.size()));
249
Christopher Ferris4568f4b2018-10-23 17:42:41 -0700250 Elf* elf = info.GetElf(process_memory_, ARCH_ARM);
Christopher Ferrisbe788d82017-11-27 14:50:38 -0800251 ASSERT_TRUE(elf != nullptr);
Christopher Ferris5f118512017-09-01 11:17:16 -0700252 ASSERT_TRUE(elf->valid());
253 ASSERT_TRUE(elf->memory() != nullptr);
254 ASSERT_EQ(0U, info.elf_offset);
255
256 // Verify the memory is a valid elf.
257 memset(buffer.data(), 0, buffer.size());
Josh Gaoef35aa52017-10-18 11:44:51 -0700258 ASSERT_TRUE(elf->memory()->ReadFully(0, buffer.data(), 0x1000));
Christopher Ferris5f118512017-09-01 11:17:16 -0700259 ASSERT_EQ(0, memcmp(buffer.data(), &ehdr, sizeof(ehdr)));
260
261 // Read past the end of what would normally be the size of the map.
Josh Gaoef35aa52017-10-18 11:44:51 -0700262 ASSERT_TRUE(elf->memory()->ReadFully(0x1000, buffer.data(), 1));
Christopher Ferris5f118512017-09-01 11:17:16 -0700263}
264
265TEST_F(MapInfoGetElfTest, file_backed_non_zero_offset_partial_file_whole_elf64) {
Christopher Ferris9d5712c2018-10-01 21:01:09 -0700266 MapInfo info(nullptr, 0x7000, 0x8000, 0x1000, PROT_READ, elf_.path);
Christopher Ferris5f118512017-09-01 11:17:16 -0700267
268 std::vector<uint8_t> buffer(0x4000);
269 memset(buffer.data(), 0, buffer.size());
270 Elf64_Ehdr ehdr;
271 TestInitEhdr<Elf64_Ehdr>(&ehdr, ELFCLASS64, EM_AARCH64);
272 ehdr.e_shoff = 0x2000;
273 ehdr.e_shentsize = sizeof(Elf64_Shdr) + 100;
274 ehdr.e_shnum = 4;
275 memcpy(&buffer[info.offset], &ehdr, sizeof(ehdr));
276 ASSERT_TRUE(android::base::WriteFully(elf_.fd, buffer.data(), buffer.size()));
277
Christopher Ferris4568f4b2018-10-23 17:42:41 -0700278 Elf* elf = info.GetElf(process_memory_, ARCH_ARM64);
Christopher Ferrisbe788d82017-11-27 14:50:38 -0800279 ASSERT_TRUE(elf != nullptr);
Christopher Ferris5f118512017-09-01 11:17:16 -0700280 ASSERT_TRUE(elf->valid());
281 ASSERT_TRUE(elf->memory() != nullptr);
282 ASSERT_EQ(0U, info.elf_offset);
283
284 // Verify the memory is a valid elf.
285 memset(buffer.data(), 0, buffer.size());
Josh Gaoef35aa52017-10-18 11:44:51 -0700286 ASSERT_TRUE(elf->memory()->ReadFully(0, buffer.data(), 0x1000));
Christopher Ferris5f118512017-09-01 11:17:16 -0700287 ASSERT_EQ(0, memcmp(buffer.data(), &ehdr, sizeof(ehdr)));
288
289 // Read past the end of what would normally be the size of the map.
Josh Gaoef35aa52017-10-18 11:44:51 -0700290 ASSERT_TRUE(elf->memory()->ReadFully(0x1000, buffer.data(), 1));
Christopher Ferris5f118512017-09-01 11:17:16 -0700291}
292
293TEST_F(MapInfoGetElfTest, process_memory_not_read_only) {
Christopher Ferris9d5712c2018-10-01 21:01:09 -0700294 MapInfo info(nullptr, 0x9000, 0xa000, 0x1000, 0, "");
Christopher Ferris5f118512017-09-01 11:17:16 -0700295
296 // Create valid elf data in process memory only.
297 Elf64_Ehdr ehdr;
298 TestInitEhdr<Elf64_Ehdr>(&ehdr, ELFCLASS64, EM_AARCH64);
299 ehdr.e_shoff = 0x2000;
300 ehdr.e_shentsize = sizeof(Elf64_Shdr) + 100;
Christopher Ferris5acf0692018-08-01 13:10:46 -0700301 ehdr.e_shnum = 0;
Christopher Ferris5f118512017-09-01 11:17:16 -0700302 memory_->SetMemory(0x9000, &ehdr, sizeof(ehdr));
303
Christopher Ferris4568f4b2018-10-23 17:42:41 -0700304 Elf* elf = info.GetElf(process_memory_, ARCH_ARM64);
Christopher Ferrisbe788d82017-11-27 14:50:38 -0800305 ASSERT_TRUE(elf != nullptr);
Christopher Ferris5f118512017-09-01 11:17:16 -0700306 ASSERT_FALSE(elf->valid());
307
Christopher Ferris0b79ae12018-01-25 12:15:56 -0800308 info.elf.reset();
Christopher Ferris5f118512017-09-01 11:17:16 -0700309 info.flags = PROT_READ;
Christopher Ferris4568f4b2018-10-23 17:42:41 -0700310 elf = info.GetElf(process_memory_, ARCH_ARM64);
Christopher Ferris5f118512017-09-01 11:17:16 -0700311 ASSERT_TRUE(elf->valid());
312}
313
314TEST_F(MapInfoGetElfTest, check_device_maps) {
Christopher Ferris9d5712c2018-10-01 21:01:09 -0700315 MapInfo info(nullptr, 0x7000, 0x8000, 0x1000, PROT_READ | MAPS_FLAGS_DEVICE_MAP,
316 "/dev/something");
Christopher Ferris5f118512017-09-01 11:17:16 -0700317
318 // Create valid elf data in process memory for this to verify that only
319 // the name is causing invalid elf data.
320 Elf64_Ehdr ehdr;
321 TestInitEhdr<Elf64_Ehdr>(&ehdr, ELFCLASS64, EM_X86_64);
322 ehdr.e_shoff = 0x2000;
323 ehdr.e_shentsize = sizeof(Elf64_Shdr) + 100;
Christopher Ferris5acf0692018-08-01 13:10:46 -0700324 ehdr.e_shnum = 0;
Christopher Ferris5f118512017-09-01 11:17:16 -0700325 memory_->SetMemory(0x7000, &ehdr, sizeof(ehdr));
326
Christopher Ferris4568f4b2018-10-23 17:42:41 -0700327 Elf* elf = info.GetElf(process_memory_, ARCH_X86_64);
Christopher Ferrisbe788d82017-11-27 14:50:38 -0800328 ASSERT_TRUE(elf != nullptr);
Christopher Ferris5f118512017-09-01 11:17:16 -0700329 ASSERT_FALSE(elf->valid());
330
331 // Set the name to nothing to verify that it still fails.
Christopher Ferris0b79ae12018-01-25 12:15:56 -0800332 info.elf.reset();
Christopher Ferris5f118512017-09-01 11:17:16 -0700333 info.name = "";
Christopher Ferris4568f4b2018-10-23 17:42:41 -0700334 elf = info.GetElf(process_memory_, ARCH_X86_64);
Christopher Ferris5f118512017-09-01 11:17:16 -0700335 ASSERT_FALSE(elf->valid());
336
337 // Change the flags and verify the elf is valid now.
Christopher Ferris0b79ae12018-01-25 12:15:56 -0800338 info.elf.reset();
Christopher Ferris5f118512017-09-01 11:17:16 -0700339 info.flags = PROT_READ;
Christopher Ferris4568f4b2018-10-23 17:42:41 -0700340 elf = info.GetElf(process_memory_, ARCH_X86_64);
Christopher Ferris5f118512017-09-01 11:17:16 -0700341 ASSERT_TRUE(elf->valid());
342}
343
Christopher Ferrisbe788d82017-11-27 14:50:38 -0800344TEST_F(MapInfoGetElfTest, multiple_thread_get_elf) {
345 static constexpr size_t kNumConcurrentThreads = 100;
346
347 Elf64_Ehdr ehdr;
348 TestInitEhdr<Elf64_Ehdr>(&ehdr, ELFCLASS64, EM_X86_64);
349 ehdr.e_shoff = 0x2000;
350 ehdr.e_shentsize = sizeof(Elf64_Shdr) + 100;
Christopher Ferris5acf0692018-08-01 13:10:46 -0700351 ehdr.e_shnum = 0;
Christopher Ferrisbe788d82017-11-27 14:50:38 -0800352 memory_->SetMemory(0x7000, &ehdr, sizeof(ehdr));
353
354 Elf* elf_in_threads[kNumConcurrentThreads];
355 std::vector<std::thread*> threads;
356
357 std::atomic_bool wait;
358 wait = true;
359 // Create all of the threads and have them do the GetElf at the same time
360 // to make it likely that a race will occur.
Christopher Ferris9d5712c2018-10-01 21:01:09 -0700361 MapInfo info(nullptr, 0x7000, 0x8000, 0x1000, PROT_READ, "");
Christopher Ferrisbe788d82017-11-27 14:50:38 -0800362 for (size_t i = 0; i < kNumConcurrentThreads; i++) {
363 std::thread* thread = new std::thread([i, this, &wait, &info, &elf_in_threads]() {
364 while (wait)
365 ;
Christopher Ferris4568f4b2018-10-23 17:42:41 -0700366 Elf* elf = info.GetElf(process_memory_, ARCH_X86_64);
Christopher Ferrisbe788d82017-11-27 14:50:38 -0800367 elf_in_threads[i] = elf;
368 });
369 threads.push_back(thread);
370 }
371 ASSERT_TRUE(info.elf == nullptr);
372
373 // Set them all going and wait for the threads to finish.
374 wait = false;
375 for (auto thread : threads) {
376 thread->join();
377 delete thread;
378 }
379
380 // Now verify that all of the elf files are exactly the same and valid.
Christopher Ferris0b79ae12018-01-25 12:15:56 -0800381 Elf* elf = info.elf.get();
Christopher Ferrisbe788d82017-11-27 14:50:38 -0800382 ASSERT_TRUE(elf != nullptr);
383 EXPECT_TRUE(elf->valid());
384 for (size_t i = 0; i < kNumConcurrentThreads; i++) {
385 EXPECT_EQ(elf, elf_in_threads[i]) << "Thread " << i << " mismatched.";
386 }
387}
388
Christopher Ferrisd226a512017-07-14 10:37:19 -0700389} // namespace unwindstack