blob: 866b5b4ef2c1aab2913dd99fe29c07912055814c [file] [log] [blame]
Christopher Ferris0d7cf3e2017-04-19 15:42:19 -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
26#include <memory>
27#include <vector>
28
29#include <android-base/file.h>
30#include <android-base/test_utils.h>
31#include <gtest/gtest.h>
32
Christopher Ferrisd226a512017-07-14 10:37:19 -070033#include <unwindstack/Elf.h>
34#include <unwindstack/MapInfo.h>
35#include <unwindstack/Memory.h>
36
Christopher Ferris5f118512017-09-01 11:17:16 -070037#include "MemoryFake.h"
38
Christopher Ferrisd226a512017-07-14 10:37:19 -070039namespace unwindstack {
Christopher Ferris0d7cf3e2017-04-19 15:42:19 -070040
Christopher Ferris570b76f2017-06-30 17:18:16 -070041class MapInfoCreateMemoryTest : public ::testing::Test {
Christopher Ferris0d7cf3e2017-04-19 15:42:19 -070042 protected:
Christopher Ferris3f805ac2017-08-30 13:15:19 -070043 template <typename Ehdr, typename Shdr>
44 static void InitElf(int fd, uint64_t file_offset, uint64_t sh_offset, uint8_t class_type) {
45 std::vector<uint8_t> buffer(20000);
46 memset(buffer.data(), 0, buffer.size());
47
48 Ehdr ehdr;
49 memset(&ehdr, 0, sizeof(ehdr));
50 memcpy(ehdr.e_ident, ELFMAG, SELFMAG);
51 ehdr.e_ident[EI_CLASS] = class_type;
52 ehdr.e_shoff = sh_offset;
53 ehdr.e_shentsize = sizeof(Shdr) + 100;
54 ehdr.e_shnum = 4;
55 memcpy(&buffer[file_offset], &ehdr, sizeof(ehdr));
56
57 ASSERT_TRUE(android::base::WriteFully(fd, buffer.data(), buffer.size()));
58 }
59
Christopher Ferris0d7cf3e2017-04-19 15:42:19 -070060 static void SetUpTestCase() {
61 std::vector<uint8_t> buffer(1024);
Christopher Ferris3f805ac2017-08-30 13:15:19 -070062 memset(buffer.data(), 0, buffer.size());
Christopher Ferris0d7cf3e2017-04-19 15:42:19 -070063 memcpy(buffer.data(), ELFMAG, SELFMAG);
Christopher Ferris3f805ac2017-08-30 13:15:19 -070064 buffer[EI_CLASS] = ELFCLASS32;
Christopher Ferris0d7cf3e2017-04-19 15:42:19 -070065 ASSERT_TRUE(android::base::WriteFully(elf_.fd, buffer.data(), buffer.size()));
66
Christopher Ferris3f805ac2017-08-30 13:15:19 -070067 memset(buffer.data(), 0, buffer.size());
Christopher Ferris0d7cf3e2017-04-19 15:42:19 -070068 memcpy(&buffer[0x100], ELFMAG, SELFMAG);
Christopher Ferris3f805ac2017-08-30 13:15:19 -070069 buffer[0x100 + EI_CLASS] = ELFCLASS64;
Christopher Ferris0d7cf3e2017-04-19 15:42:19 -070070 ASSERT_TRUE(android::base::WriteFully(elf_at_100_.fd, buffer.data(), buffer.size()));
Christopher Ferris3f805ac2017-08-30 13:15:19 -070071
72 InitElf<Elf32_Ehdr, Elf32_Shdr>(elf32_at_map_.fd, 0x1000, 0x2000, ELFCLASS32);
73 InitElf<Elf64_Ehdr, Elf64_Shdr>(elf64_at_map_.fd, 0x2000, 0x3000, ELFCLASS64);
Christopher Ferris0d7cf3e2017-04-19 15:42:19 -070074 }
75
Christopher Ferris5f118512017-09-01 11:17:16 -070076 void SetUp() override {
77 memory_ = new MemoryFake;
78 process_memory_.reset(memory_);
79 }
80
81 MemoryFake* memory_;
82 std::shared_ptr<Memory> process_memory_;
83
Christopher Ferris0d7cf3e2017-04-19 15:42:19 -070084 static TemporaryFile elf_;
85
86 static TemporaryFile elf_at_100_;
Christopher Ferris3f805ac2017-08-30 13:15:19 -070087
88 static TemporaryFile elf32_at_map_;
89 static TemporaryFile elf64_at_map_;
Christopher Ferris0d7cf3e2017-04-19 15:42:19 -070090};
Christopher Ferris570b76f2017-06-30 17:18:16 -070091TemporaryFile MapInfoCreateMemoryTest::elf_;
92TemporaryFile MapInfoCreateMemoryTest::elf_at_100_;
Christopher Ferris3f805ac2017-08-30 13:15:19 -070093TemporaryFile MapInfoCreateMemoryTest::elf32_at_map_;
94TemporaryFile MapInfoCreateMemoryTest::elf64_at_map_;
Christopher Ferris0d7cf3e2017-04-19 15:42:19 -070095
Christopher Ferris570b76f2017-06-30 17:18:16 -070096TEST_F(MapInfoCreateMemoryTest, end_le_start) {
Christopher Ferrisbe788d82017-11-27 14:50:38 -080097 MapInfo info(0x100, 0x100, 0, 0, elf_.path);
Christopher Ferris0d7cf3e2017-04-19 15:42:19 -070098
Christopher Ferris5f118512017-09-01 11:17:16 -070099 std::unique_ptr<Memory> memory(info.CreateMemory(process_memory_));
Christopher Ferris0d7cf3e2017-04-19 15:42:19 -0700100 ASSERT_TRUE(memory.get() == nullptr);
101
102 info.end = 0xff;
Christopher Ferris5f118512017-09-01 11:17:16 -0700103 memory.reset(info.CreateMemory(process_memory_));
Christopher Ferris0d7cf3e2017-04-19 15:42:19 -0700104 ASSERT_TRUE(memory.get() == nullptr);
105
106 // Make sure this test is valid.
107 info.end = 0x101;
Christopher Ferris5f118512017-09-01 11:17:16 -0700108 memory.reset(info.CreateMemory(process_memory_));
Christopher Ferris051792f2017-06-19 13:42:04 -0700109 ASSERT_TRUE(memory.get() != nullptr);
Christopher Ferris0d7cf3e2017-04-19 15:42:19 -0700110}
111
112// Verify that if the offset is non-zero but there is no elf at the offset,
113// that the full file is used.
Christopher Ferris570b76f2017-06-30 17:18:16 -0700114TEST_F(MapInfoCreateMemoryTest, file_backed_non_zero_offset_full_file) {
Christopher Ferrisbe788d82017-11-27 14:50:38 -0800115 MapInfo info(0x100, 0x200, 0x100, 0, elf_.path);
Christopher Ferris0d7cf3e2017-04-19 15:42:19 -0700116
Christopher Ferris5f118512017-09-01 11:17:16 -0700117 std::unique_ptr<Memory> memory(info.CreateMemory(process_memory_));
Christopher Ferris0d7cf3e2017-04-19 15:42:19 -0700118 ASSERT_TRUE(memory.get() != nullptr);
119 ASSERT_EQ(0x100U, info.elf_offset);
120
121 // Read the entire file.
122 std::vector<uint8_t> buffer(1024);
Josh Gaoef35aa52017-10-18 11:44:51 -0700123 ASSERT_TRUE(memory->ReadFully(0, buffer.data(), 1024));
Christopher Ferris0d7cf3e2017-04-19 15:42:19 -0700124 ASSERT_TRUE(memcmp(buffer.data(), ELFMAG, SELFMAG) == 0);
Christopher Ferris3f805ac2017-08-30 13:15:19 -0700125 ASSERT_EQ(ELFCLASS32, buffer[EI_CLASS]);
126 for (size_t i = EI_CLASS + 1; i < buffer.size(); i++) {
127 ASSERT_EQ(0, buffer[i]) << "Failed at byte " << i;
Christopher Ferris0d7cf3e2017-04-19 15:42:19 -0700128 }
129
Josh Gaoef35aa52017-10-18 11:44:51 -0700130 ASSERT_FALSE(memory->ReadFully(1024, buffer.data(), 1));
Christopher Ferris0d7cf3e2017-04-19 15:42:19 -0700131}
132
133// Verify that if the offset is non-zero and there is an elf at that
134// offset, that only part of the file is used.
Christopher Ferris570b76f2017-06-30 17:18:16 -0700135TEST_F(MapInfoCreateMemoryTest, file_backed_non_zero_offset_partial_file) {
Christopher Ferrisbe788d82017-11-27 14:50:38 -0800136 MapInfo info(0x100, 0x200, 0x100, 0, elf_at_100_.path);
Christopher Ferris0d7cf3e2017-04-19 15:42:19 -0700137
Christopher Ferris5f118512017-09-01 11:17:16 -0700138 std::unique_ptr<Memory> memory(info.CreateMemory(process_memory_));
Christopher Ferris0d7cf3e2017-04-19 15:42:19 -0700139 ASSERT_TRUE(memory.get() != nullptr);
140 ASSERT_EQ(0U, info.elf_offset);
141
142 // Read the valid part of the file.
143 std::vector<uint8_t> buffer(0x100);
Josh Gaoef35aa52017-10-18 11:44:51 -0700144 ASSERT_TRUE(memory->ReadFully(0, buffer.data(), 0x100));
Christopher Ferris0d7cf3e2017-04-19 15:42:19 -0700145 ASSERT_TRUE(memcmp(buffer.data(), ELFMAG, SELFMAG) == 0);
Christopher Ferris3f805ac2017-08-30 13:15:19 -0700146 ASSERT_EQ(ELFCLASS64, buffer[EI_CLASS]);
147 for (size_t i = EI_CLASS + 1; i < buffer.size(); i++) {
148 ASSERT_EQ(0, buffer[i]) << "Failed at byte " << i;
Christopher Ferris0d7cf3e2017-04-19 15:42:19 -0700149 }
150
Josh Gaoef35aa52017-10-18 11:44:51 -0700151 ASSERT_FALSE(memory->ReadFully(0x100, buffer.data(), 1));
Christopher Ferris0d7cf3e2017-04-19 15:42:19 -0700152}
153
Christopher Ferris3f805ac2017-08-30 13:15:19 -0700154// Verify that if the offset is non-zero and there is an elf at that
155// offset, that only part of the file is used. Further verify that if the
156// embedded elf is bigger than the initial map, the new object is larger
157// than the original map size. Do this for a 32 bit elf and a 64 bit elf.
158TEST_F(MapInfoCreateMemoryTest, file_backed_non_zero_offset_partial_file_whole_elf32) {
Christopher Ferrisbe788d82017-11-27 14:50:38 -0800159 MapInfo info(0x5000, 0x6000, 0x1000, 0, elf32_at_map_.path);
Christopher Ferris3f805ac2017-08-30 13:15:19 -0700160
Christopher Ferris5f118512017-09-01 11:17:16 -0700161 std::unique_ptr<Memory> memory(info.CreateMemory(process_memory_));
Christopher Ferris3f805ac2017-08-30 13:15:19 -0700162 ASSERT_TRUE(memory.get() != nullptr);
163 ASSERT_EQ(0U, info.elf_offset);
164
165 // Verify the memory is a valid elf.
166 uint8_t e_ident[SELFMAG + 1];
Josh Gaoef35aa52017-10-18 11:44:51 -0700167 ASSERT_TRUE(memory->ReadFully(0, e_ident, SELFMAG));
Christopher Ferris3f805ac2017-08-30 13:15:19 -0700168 ASSERT_EQ(0, memcmp(e_ident, ELFMAG, SELFMAG));
169
170 // Read past the end of what would normally be the size of the map.
Josh Gaoef35aa52017-10-18 11:44:51 -0700171 ASSERT_TRUE(memory->ReadFully(0x1000, e_ident, 1));
Christopher Ferris3f805ac2017-08-30 13:15:19 -0700172}
173
174TEST_F(MapInfoCreateMemoryTest, file_backed_non_zero_offset_partial_file_whole_elf64) {
Christopher Ferrisbe788d82017-11-27 14:50:38 -0800175 MapInfo info(0x7000, 0x8000, 0x2000, 0, elf64_at_map_.path);
Christopher Ferris3f805ac2017-08-30 13:15:19 -0700176
Christopher Ferris5f118512017-09-01 11:17:16 -0700177 std::unique_ptr<Memory> memory(info.CreateMemory(process_memory_));
Christopher Ferris3f805ac2017-08-30 13:15:19 -0700178 ASSERT_TRUE(memory.get() != nullptr);
179 ASSERT_EQ(0U, info.elf_offset);
180
181 // Verify the memory is a valid elf.
182 uint8_t e_ident[SELFMAG + 1];
Josh Gaoef35aa52017-10-18 11:44:51 -0700183 ASSERT_TRUE(memory->ReadFully(0, e_ident, SELFMAG));
Christopher Ferris3f805ac2017-08-30 13:15:19 -0700184 ASSERT_EQ(0, memcmp(e_ident, ELFMAG, SELFMAG));
185
186 // Read past the end of what would normally be the size of the map.
Josh Gaoef35aa52017-10-18 11:44:51 -0700187 ASSERT_TRUE(memory->ReadFully(0x1000, e_ident, 1));
Christopher Ferris3f805ac2017-08-30 13:15:19 -0700188}
189
Christopher Ferris0d7cf3e2017-04-19 15:42:19 -0700190// Verify that device file names will never result in Memory object creation.
Christopher Ferris570b76f2017-06-30 17:18:16 -0700191TEST_F(MapInfoCreateMemoryTest, check_device_maps) {
Christopher Ferris0d7cf3e2017-04-19 15:42:19 -0700192 // Set up some memory so that a valid local memory object would
193 // be returned if the file mapping fails, but the device check is incorrect.
194 std::vector<uint8_t> buffer(1024);
195 MapInfo info;
196 info.start = reinterpret_cast<uint64_t>(buffer.data());
197 info.end = info.start + buffer.size();
198 info.offset = 0;
Christopher Ferris0d7cf3e2017-04-19 15:42:19 -0700199
200 info.flags = 0x8000;
201 info.name = "/dev/something";
Christopher Ferris5f118512017-09-01 11:17:16 -0700202 std::unique_ptr<Memory> memory(info.CreateMemory(process_memory_));
Christopher Ferris0d7cf3e2017-04-19 15:42:19 -0700203 ASSERT_TRUE(memory.get() == nullptr);
204}
205
Christopher Ferris5f118512017-09-01 11:17:16 -0700206TEST_F(MapInfoCreateMemoryTest, process_memory) {
207 MapInfo info;
208 info.start = 0x2000;
209 info.end = 0x3000;
210 info.offset = 0;
211
212 // Verify that the the process_memory object is used, so seed it
213 // with memory.
Christopher Ferris0d7cf3e2017-04-19 15:42:19 -0700214 std::vector<uint8_t> buffer(1024);
215 for (size_t i = 0; i < buffer.size(); i++) {
216 buffer[i] = i % 256;
217 }
Christopher Ferris5f118512017-09-01 11:17:16 -0700218 memory_->SetMemory(info.start, buffer.data(), buffer.size());
Christopher Ferris0d7cf3e2017-04-19 15:42:19 -0700219
Christopher Ferris5f118512017-09-01 11:17:16 -0700220 std::unique_ptr<Memory> memory(info.CreateMemory(process_memory_));
Christopher Ferris0d7cf3e2017-04-19 15:42:19 -0700221 ASSERT_TRUE(memory.get() != nullptr);
222
Christopher Ferris5f118512017-09-01 11:17:16 -0700223 memset(buffer.data(), 0, buffer.size());
Josh Gaoef35aa52017-10-18 11:44:51 -0700224 ASSERT_TRUE(memory->ReadFully(0, buffer.data(), buffer.size()));
Christopher Ferris5f118512017-09-01 11:17:16 -0700225 for (size_t i = 0; i < buffer.size(); i++) {
226 ASSERT_EQ(i % 256, buffer[i]) << "Failed at byte " << i;
Christopher Ferris0d7cf3e2017-04-19 15:42:19 -0700227 }
228
Christopher Ferris5f118512017-09-01 11:17:16 -0700229 // Try to read outside of the map size.
Josh Gaoef35aa52017-10-18 11:44:51 -0700230 ASSERT_FALSE(memory->ReadFully(buffer.size(), buffer.data(), 1));
Christopher Ferris0d7cf3e2017-04-19 15:42:19 -0700231}
Christopher Ferrisd226a512017-07-14 10:37:19 -0700232
233} // namespace unwindstack