| Christopher Ferris | 3958f80 | 2017-02-01 15:44:40 -0800 | [diff] [blame] | 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> | 
| Christopher Ferris | bae69f1 | 2017-06-28 14:51:54 -0700 | [diff] [blame] | 18 | #include <fcntl.h> | 
|  | 19 | #include <sys/stat.h> | 
|  | 20 | #include <sys/types.h> | 
|  | 21 | #include <unistd.h> | 
| Christopher Ferris | 3958f80 | 2017-02-01 15:44:40 -0800 | [diff] [blame] | 22 |  | 
|  | 23 | #include <gtest/gtest.h> | 
|  | 24 |  | 
| Christopher Ferris | d226a51 | 2017-07-14 10:37:19 -0700 | [diff] [blame] | 25 | #include <unwindstack/Elf.h> | 
|  | 26 | #include <unwindstack/MapInfo.h> | 
| Christopher Ferris | 3958f80 | 2017-02-01 15:44:40 -0800 | [diff] [blame] | 27 |  | 
| Christopher Ferris | 570b76f | 2017-06-30 17:18:16 -0700 | [diff] [blame] | 28 | #include "ElfTestUtils.h" | 
| Christopher Ferris | a019665 | 2017-07-18 16:09:20 -0700 | [diff] [blame] | 29 | #include "LogFake.h" | 
| Christopher Ferris | 3958f80 | 2017-02-01 15:44:40 -0800 | [diff] [blame] | 30 | #include "MemoryFake.h" | 
|  | 31 |  | 
|  | 32 | #if !defined(PT_ARM_EXIDX) | 
|  | 33 | #define PT_ARM_EXIDX 0x70000001 | 
|  | 34 | #endif | 
|  | 35 |  | 
| Christopher Ferris | d226a51 | 2017-07-14 10:37:19 -0700 | [diff] [blame] | 36 | namespace unwindstack { | 
|  | 37 |  | 
| Christopher Ferris | 3958f80 | 2017-02-01 15:44:40 -0800 | [diff] [blame] | 38 | class ElfTest : public ::testing::Test { | 
|  | 39 | protected: | 
|  | 40 | void SetUp() override { | 
|  | 41 | memory_ = new MemoryFake; | 
|  | 42 | } | 
|  | 43 |  | 
| Christopher Ferris | 570b76f | 2017-06-30 17:18:16 -0700 | [diff] [blame] | 44 | void InitElf32(uint32_t machine_type) { | 
| Christopher Ferris | 3958f80 | 2017-02-01 15:44:40 -0800 | [diff] [blame] | 45 | Elf32_Ehdr ehdr; | 
| Christopher Ferris | 570b76f | 2017-06-30 17:18:16 -0700 | [diff] [blame] | 46 | TestInitEhdr<Elf32_Ehdr>(&ehdr, ELFCLASS32, machine_type); | 
| Christopher Ferris | 3958f80 | 2017-02-01 15:44:40 -0800 | [diff] [blame] | 47 |  | 
| Christopher Ferris | 3958f80 | 2017-02-01 15:44:40 -0800 | [diff] [blame] | 48 | ehdr.e_phoff = 0x100; | 
| Christopher Ferris | 3958f80 | 2017-02-01 15:44:40 -0800 | [diff] [blame] | 49 | ehdr.e_ehsize = sizeof(ehdr); | 
|  | 50 | ehdr.e_phentsize = sizeof(Elf32_Phdr); | 
|  | 51 | ehdr.e_phnum = 1; | 
|  | 52 | ehdr.e_shentsize = sizeof(Elf32_Shdr); | 
| Christopher Ferris | 570b76f | 2017-06-30 17:18:16 -0700 | [diff] [blame] | 53 | if (machine_type == EM_ARM) { | 
| Christopher Ferris | 3958f80 | 2017-02-01 15:44:40 -0800 | [diff] [blame] | 54 | ehdr.e_flags = 0x5000200; | 
|  | 55 | ehdr.e_phnum = 2; | 
|  | 56 | } | 
|  | 57 | memory_->SetMemory(0, &ehdr, sizeof(ehdr)); | 
|  | 58 |  | 
|  | 59 | Elf32_Phdr phdr; | 
|  | 60 | memset(&phdr, 0, sizeof(phdr)); | 
|  | 61 | phdr.p_type = PT_LOAD; | 
| Christopher Ferris | 3958f80 | 2017-02-01 15:44:40 -0800 | [diff] [blame] | 62 | phdr.p_filesz = 0x10000; | 
|  | 63 | phdr.p_memsz = 0x10000; | 
|  | 64 | phdr.p_flags = PF_R | PF_X; | 
|  | 65 | phdr.p_align = 0x1000; | 
|  | 66 | memory_->SetMemory(0x100, &phdr, sizeof(phdr)); | 
|  | 67 |  | 
| Christopher Ferris | 570b76f | 2017-06-30 17:18:16 -0700 | [diff] [blame] | 68 | if (machine_type == EM_ARM) { | 
| Christopher Ferris | 3958f80 | 2017-02-01 15:44:40 -0800 | [diff] [blame] | 69 | memset(&phdr, 0, sizeof(phdr)); | 
|  | 70 | phdr.p_type = PT_ARM_EXIDX; | 
|  | 71 | phdr.p_offset = 0x30000; | 
|  | 72 | phdr.p_vaddr = 0x30000; | 
|  | 73 | phdr.p_paddr = 0x30000; | 
|  | 74 | phdr.p_filesz = 16; | 
|  | 75 | phdr.p_memsz = 16; | 
|  | 76 | phdr.p_flags = PF_R; | 
|  | 77 | phdr.p_align = 0x4; | 
|  | 78 | memory_->SetMemory(0x100 + sizeof(phdr), &phdr, sizeof(phdr)); | 
|  | 79 | } | 
|  | 80 | } | 
|  | 81 |  | 
| Christopher Ferris | 570b76f | 2017-06-30 17:18:16 -0700 | [diff] [blame] | 82 | void InitElf64(uint32_t machine_type) { | 
| Christopher Ferris | 3958f80 | 2017-02-01 15:44:40 -0800 | [diff] [blame] | 83 | Elf64_Ehdr ehdr; | 
| Christopher Ferris | 570b76f | 2017-06-30 17:18:16 -0700 | [diff] [blame] | 84 | TestInitEhdr<Elf64_Ehdr>(&ehdr, ELFCLASS64, machine_type); | 
| Christopher Ferris | 3958f80 | 2017-02-01 15:44:40 -0800 | [diff] [blame] | 85 |  | 
| Christopher Ferris | 3958f80 | 2017-02-01 15:44:40 -0800 | [diff] [blame] | 86 | ehdr.e_phoff = 0x100; | 
| Christopher Ferris | 3958f80 | 2017-02-01 15:44:40 -0800 | [diff] [blame] | 87 | ehdr.e_flags = 0x5000200; | 
|  | 88 | ehdr.e_ehsize = sizeof(ehdr); | 
|  | 89 | ehdr.e_phentsize = sizeof(Elf64_Phdr); | 
|  | 90 | ehdr.e_phnum = 1; | 
|  | 91 | ehdr.e_shentsize = sizeof(Elf64_Shdr); | 
| Christopher Ferris | 3958f80 | 2017-02-01 15:44:40 -0800 | [diff] [blame] | 92 | memory_->SetMemory(0, &ehdr, sizeof(ehdr)); | 
|  | 93 |  | 
|  | 94 | Elf64_Phdr phdr; | 
|  | 95 | memset(&phdr, 0, sizeof(phdr)); | 
|  | 96 | phdr.p_type = PT_LOAD; | 
| Christopher Ferris | 3958f80 | 2017-02-01 15:44:40 -0800 | [diff] [blame] | 97 | phdr.p_filesz = 0x10000; | 
|  | 98 | phdr.p_memsz = 0x10000; | 
|  | 99 | phdr.p_flags = PF_R | PF_X; | 
|  | 100 | phdr.p_align = 0x1000; | 
|  | 101 | memory_->SetMemory(0x100, &phdr, sizeof(phdr)); | 
|  | 102 | } | 
|  | 103 |  | 
|  | 104 | MemoryFake* memory_; | 
|  | 105 | }; | 
|  | 106 |  | 
|  | 107 | TEST_F(ElfTest, invalid_memory) { | 
|  | 108 | Elf elf(memory_); | 
|  | 109 |  | 
|  | 110 | ASSERT_FALSE(elf.Init()); | 
|  | 111 | ASSERT_FALSE(elf.valid()); | 
|  | 112 | } | 
|  | 113 |  | 
|  | 114 | TEST_F(ElfTest, elf_invalid) { | 
|  | 115 | Elf elf(memory_); | 
|  | 116 |  | 
|  | 117 | InitElf32(EM_386); | 
|  | 118 |  | 
|  | 119 | // Corrupt the ELF signature. | 
|  | 120 | memory_->SetData32(0, 0x7f000000); | 
|  | 121 |  | 
|  | 122 | ASSERT_FALSE(elf.Init()); | 
|  | 123 | ASSERT_FALSE(elf.valid()); | 
|  | 124 | ASSERT_TRUE(elf.interface() == nullptr); | 
|  | 125 |  | 
|  | 126 | std::string name; | 
|  | 127 | ASSERT_FALSE(elf.GetSoname(&name)); | 
|  | 128 |  | 
|  | 129 | uint64_t func_offset; | 
|  | 130 | ASSERT_FALSE(elf.GetFunctionName(0, &name, &func_offset)); | 
|  | 131 |  | 
| Christopher Ferris | b9de87f | 2017-09-20 13:37:24 -0700 | [diff] [blame] | 132 | bool finished; | 
|  | 133 | ASSERT_FALSE(elf.Step(0, nullptr, nullptr, &finished)); | 
| Christopher Ferris | 3958f80 | 2017-02-01 15:44:40 -0800 | [diff] [blame] | 134 | } | 
|  | 135 |  | 
| Christopher Ferris | a019665 | 2017-07-18 16:09:20 -0700 | [diff] [blame] | 136 | TEST_F(ElfTest, elf32_invalid_machine) { | 
|  | 137 | Elf elf(memory_); | 
|  | 138 |  | 
|  | 139 | InitElf32(EM_PPC); | 
|  | 140 |  | 
|  | 141 | ResetLogs(); | 
|  | 142 | ASSERT_FALSE(elf.Init()); | 
|  | 143 |  | 
|  | 144 | ASSERT_EQ("", GetFakeLogBuf()); | 
|  | 145 | ASSERT_EQ("4 unwind 32 bit elf that is neither arm nor x86: e_machine = 20\n\n", | 
|  | 146 | GetFakeLogPrint()); | 
|  | 147 | } | 
|  | 148 |  | 
|  | 149 | TEST_F(ElfTest, elf64_invalid_machine) { | 
|  | 150 | Elf elf(memory_); | 
|  | 151 |  | 
|  | 152 | InitElf64(EM_PPC64); | 
|  | 153 |  | 
|  | 154 | ResetLogs(); | 
|  | 155 | ASSERT_FALSE(elf.Init()); | 
|  | 156 |  | 
|  | 157 | ASSERT_EQ("", GetFakeLogBuf()); | 
|  | 158 | ASSERT_EQ("4 unwind 64 bit elf that is neither aarch64 nor x86_64: e_machine = 21\n\n", | 
|  | 159 | GetFakeLogPrint()); | 
|  | 160 | } | 
|  | 161 |  | 
| Christopher Ferris | 3958f80 | 2017-02-01 15:44:40 -0800 | [diff] [blame] | 162 | TEST_F(ElfTest, elf_arm) { | 
|  | 163 | Elf elf(memory_); | 
|  | 164 |  | 
|  | 165 | InitElf32(EM_ARM); | 
|  | 166 |  | 
|  | 167 | ASSERT_TRUE(elf.Init()); | 
|  | 168 | ASSERT_TRUE(elf.valid()); | 
|  | 169 | ASSERT_EQ(static_cast<uint32_t>(EM_ARM), elf.machine_type()); | 
|  | 170 | ASSERT_EQ(ELFCLASS32, elf.class_type()); | 
|  | 171 | ASSERT_TRUE(elf.interface() != nullptr); | 
|  | 172 | } | 
|  | 173 |  | 
|  | 174 | TEST_F(ElfTest, elf_x86) { | 
|  | 175 | Elf elf(memory_); | 
|  | 176 |  | 
|  | 177 | InitElf32(EM_386); | 
|  | 178 |  | 
|  | 179 | ASSERT_TRUE(elf.Init()); | 
|  | 180 | ASSERT_TRUE(elf.valid()); | 
|  | 181 | ASSERT_EQ(static_cast<uint32_t>(EM_386), elf.machine_type()); | 
|  | 182 | ASSERT_EQ(ELFCLASS32, elf.class_type()); | 
|  | 183 | ASSERT_TRUE(elf.interface() != nullptr); | 
|  | 184 | } | 
|  | 185 |  | 
|  | 186 | TEST_F(ElfTest, elf_arm64) { | 
|  | 187 | Elf elf(memory_); | 
|  | 188 |  | 
|  | 189 | InitElf64(EM_AARCH64); | 
|  | 190 |  | 
|  | 191 | ASSERT_TRUE(elf.Init()); | 
|  | 192 | ASSERT_TRUE(elf.valid()); | 
|  | 193 | ASSERT_EQ(static_cast<uint32_t>(EM_AARCH64), elf.machine_type()); | 
|  | 194 | ASSERT_EQ(ELFCLASS64, elf.class_type()); | 
|  | 195 | ASSERT_TRUE(elf.interface() != nullptr); | 
|  | 196 | } | 
|  | 197 |  | 
|  | 198 | TEST_F(ElfTest, elf_x86_64) { | 
|  | 199 | Elf elf(memory_); | 
|  | 200 |  | 
|  | 201 | InitElf64(EM_X86_64); | 
|  | 202 |  | 
|  | 203 | ASSERT_TRUE(elf.Init()); | 
|  | 204 | ASSERT_TRUE(elf.valid()); | 
|  | 205 | ASSERT_EQ(static_cast<uint32_t>(EM_X86_64), elf.machine_type()); | 
|  | 206 | ASSERT_EQ(ELFCLASS64, elf.class_type()); | 
|  | 207 | ASSERT_TRUE(elf.interface() != nullptr); | 
|  | 208 | } | 
| Christopher Ferris | bae69f1 | 2017-06-28 14:51:54 -0700 | [diff] [blame] | 209 |  | 
| Christopher Ferris | 570b76f | 2017-06-30 17:18:16 -0700 | [diff] [blame] | 210 | TEST_F(ElfTest, gnu_debugdata_init_fail32) { | 
|  | 211 | TestInitGnuDebugdata<Elf32_Ehdr, Elf32_Shdr>(ELFCLASS32, EM_ARM, false, | 
|  | 212 | [&](uint64_t offset, const void* ptr, size_t size) { | 
|  | 213 | memory_->SetMemory(offset, ptr, size); | 
|  | 214 | }); | 
|  | 215 |  | 
| Christopher Ferris | bae69f1 | 2017-06-28 14:51:54 -0700 | [diff] [blame] | 216 | Elf elf(memory_); | 
| Christopher Ferris | bae69f1 | 2017-06-28 14:51:54 -0700 | [diff] [blame] | 217 | ASSERT_TRUE(elf.Init()); | 
|  | 218 | ASSERT_TRUE(elf.interface() != nullptr); | 
|  | 219 | ASSERT_TRUE(elf.gnu_debugdata_interface() == nullptr); | 
| Christopher Ferris | 570b76f | 2017-06-30 17:18:16 -0700 | [diff] [blame] | 220 | EXPECT_EQ(0x1acU, elf.interface()->gnu_debugdata_offset()); | 
|  | 221 | EXPECT_EQ(0x100U, elf.interface()->gnu_debugdata_size()); | 
| Christopher Ferris | bae69f1 | 2017-06-28 14:51:54 -0700 | [diff] [blame] | 222 | } | 
|  | 223 |  | 
|  | 224 | TEST_F(ElfTest, gnu_debugdata_init_fail64) { | 
| Christopher Ferris | 570b76f | 2017-06-30 17:18:16 -0700 | [diff] [blame] | 225 | TestInitGnuDebugdata<Elf64_Ehdr, Elf64_Shdr>(ELFCLASS64, EM_AARCH64, false, | 
|  | 226 | [&](uint64_t offset, const void* ptr, size_t size) { | 
|  | 227 | memory_->SetMemory(offset, ptr, size); | 
|  | 228 | }); | 
| Christopher Ferris | bae69f1 | 2017-06-28 14:51:54 -0700 | [diff] [blame] | 229 |  | 
| Christopher Ferris | bae69f1 | 2017-06-28 14:51:54 -0700 | [diff] [blame] | 230 | Elf elf(memory_); | 
| Christopher Ferris | bae69f1 | 2017-06-28 14:51:54 -0700 | [diff] [blame] | 231 | ASSERT_TRUE(elf.Init()); | 
|  | 232 | ASSERT_TRUE(elf.interface() != nullptr); | 
|  | 233 | ASSERT_TRUE(elf.gnu_debugdata_interface() == nullptr); | 
| Christopher Ferris | 570b76f | 2017-06-30 17:18:16 -0700 | [diff] [blame] | 234 | EXPECT_EQ(0x200U, elf.interface()->gnu_debugdata_offset()); | 
|  | 235 | EXPECT_EQ(0x100U, elf.interface()->gnu_debugdata_size()); | 
|  | 236 | } | 
|  | 237 |  | 
|  | 238 | TEST_F(ElfTest, gnu_debugdata_init32) { | 
|  | 239 | TestInitGnuDebugdata<Elf32_Ehdr, Elf32_Shdr>(ELFCLASS32, EM_ARM, true, | 
|  | 240 | [&](uint64_t offset, const void* ptr, size_t size) { | 
|  | 241 | memory_->SetMemory(offset, ptr, size); | 
|  | 242 | }); | 
|  | 243 |  | 
|  | 244 | Elf elf(memory_); | 
|  | 245 | ASSERT_TRUE(elf.Init()); | 
|  | 246 | ASSERT_TRUE(elf.interface() != nullptr); | 
|  | 247 | ASSERT_TRUE(elf.gnu_debugdata_interface() == nullptr); | 
|  | 248 | EXPECT_EQ(0x1acU, elf.interface()->gnu_debugdata_offset()); | 
|  | 249 | EXPECT_EQ(0x8cU, elf.interface()->gnu_debugdata_size()); | 
| Christopher Ferris | bae69f1 | 2017-06-28 14:51:54 -0700 | [diff] [blame] | 250 |  | 
|  | 251 | elf.InitGnuDebugdata(); | 
|  | 252 | ASSERT_TRUE(elf.gnu_debugdata_interface() != nullptr); | 
|  | 253 | } | 
|  | 254 |  | 
| Christopher Ferris | bae69f1 | 2017-06-28 14:51:54 -0700 | [diff] [blame] | 255 | TEST_F(ElfTest, gnu_debugdata_init64) { | 
| Christopher Ferris | 570b76f | 2017-06-30 17:18:16 -0700 | [diff] [blame] | 256 | TestInitGnuDebugdata<Elf64_Ehdr, Elf64_Shdr>(ELFCLASS64, EM_AARCH64, true, | 
|  | 257 | [&](uint64_t offset, const void* ptr, size_t size) { | 
|  | 258 | memory_->SetMemory(offset, ptr, size); | 
|  | 259 | }); | 
| Christopher Ferris | bae69f1 | 2017-06-28 14:51:54 -0700 | [diff] [blame] | 260 |  | 
| Christopher Ferris | 570b76f | 2017-06-30 17:18:16 -0700 | [diff] [blame] | 261 | Elf elf(memory_); | 
|  | 262 | ASSERT_TRUE(elf.Init()); | 
|  | 263 | ASSERT_TRUE(elf.interface() != nullptr); | 
|  | 264 | ASSERT_TRUE(elf.gnu_debugdata_interface() == nullptr); | 
|  | 265 | EXPECT_EQ(0x200U, elf.interface()->gnu_debugdata_offset()); | 
|  | 266 | EXPECT_EQ(0x90U, elf.interface()->gnu_debugdata_size()); | 
|  | 267 |  | 
|  | 268 | elf.InitGnuDebugdata(); | 
|  | 269 | ASSERT_TRUE(elf.gnu_debugdata_interface() != nullptr); | 
| Christopher Ferris | bae69f1 | 2017-06-28 14:51:54 -0700 | [diff] [blame] | 270 | } | 
| Christopher Ferris | d226a51 | 2017-07-14 10:37:19 -0700 | [diff] [blame] | 271 |  | 
|  | 272 | class MockElf : public Elf { | 
|  | 273 | public: | 
|  | 274 | MockElf(Memory* memory) : Elf(memory) {} | 
|  | 275 | virtual ~MockElf() = default; | 
|  | 276 |  | 
|  | 277 | void set_valid(bool valid) { valid_ = valid; } | 
|  | 278 | void set_elf_interface(ElfInterface* interface) { interface_.reset(interface); } | 
|  | 279 | }; | 
|  | 280 |  | 
|  | 281 | TEST_F(ElfTest, rel_pc) { | 
|  | 282 | MockElf elf(memory_); | 
|  | 283 |  | 
|  | 284 | ElfInterface* interface = new ElfInterface32(memory_); | 
|  | 285 | elf.set_elf_interface(interface); | 
|  | 286 |  | 
|  | 287 | elf.set_valid(true); | 
|  | 288 | interface->set_load_bias(0); | 
|  | 289 | MapInfo map_info{.start = 0x1000, .end = 0x2000}; | 
|  | 290 |  | 
|  | 291 | ASSERT_EQ(0x101U, elf.GetRelPc(0x1101, &map_info)); | 
|  | 292 |  | 
|  | 293 | interface->set_load_bias(0x3000); | 
|  | 294 | ASSERT_EQ(0x3101U, elf.GetRelPc(0x1101, &map_info)); | 
|  | 295 |  | 
|  | 296 | elf.set_valid(false); | 
|  | 297 | ASSERT_EQ(0x101U, elf.GetRelPc(0x1101, &map_info)); | 
|  | 298 | } | 
|  | 299 |  | 
|  | 300 | }  // namespace unwindstack |