diff options
Diffstat (limited to 'libunwindstack/tests/ElfTest.cpp')
-rw-r--r-- | libunwindstack/tests/ElfTest.cpp | 177 |
1 files changed, 133 insertions, 44 deletions
diff --git a/libunwindstack/tests/ElfTest.cpp b/libunwindstack/tests/ElfTest.cpp index 25fec8e3a..ed1be3b33 100644 --- a/libunwindstack/tests/ElfTest.cpp +++ b/libunwindstack/tests/ElfTest.cpp | |||
@@ -15,20 +15,25 @@ | |||
15 | */ | 15 | */ |
16 | 16 | ||
17 | #include <elf.h> | 17 | #include <elf.h> |
18 | #include <fcntl.h> | ||
19 | #include <sys/stat.h> | ||
20 | #include <sys/types.h> | ||
21 | #include <unistd.h> | ||
18 | 22 | ||
19 | #include <gtest/gtest.h> | 23 | #include <gtest/gtest.h> |
20 | 24 | ||
21 | #include "Elf.h" | 25 | #include <unwindstack/Elf.h> |
26 | #include <unwindstack/MapInfo.h> | ||
22 | 27 | ||
28 | #include "ElfTestUtils.h" | ||
29 | #include "LogFake.h" | ||
23 | #include "MemoryFake.h" | 30 | #include "MemoryFake.h" |
24 | 31 | ||
25 | #if !defined(PT_ARM_EXIDX) | 32 | #if !defined(PT_ARM_EXIDX) |
26 | #define PT_ARM_EXIDX 0x70000001 | 33 | #define PT_ARM_EXIDX 0x70000001 |
27 | #endif | 34 | #endif |
28 | 35 | ||
29 | #if !defined(EM_AARCH64) | 36 | namespace unwindstack { |
30 | #define EM_AARCH64 183 | ||
31 | #endif | ||
32 | 37 | ||
33 | class ElfTest : public ::testing::Test { | 38 | class ElfTest : public ::testing::Test { |
34 | protected: | 39 | protected: |
@@ -36,35 +41,16 @@ class ElfTest : public ::testing::Test { | |||
36 | memory_ = new MemoryFake; | 41 | memory_ = new MemoryFake; |
37 | } | 42 | } |
38 | 43 | ||
39 | template <typename Ehdr> | 44 | void InitElf32(uint32_t machine_type) { |
40 | void InitEhdr(Ehdr* ehdr) { | ||
41 | memset(ehdr, 0, sizeof(Ehdr)); | ||
42 | memcpy(&ehdr->e_ident[0], ELFMAG, SELFMAG); | ||
43 | ehdr->e_ident[EI_DATA] = ELFDATA2LSB; | ||
44 | ehdr->e_ident[EI_VERSION] = EV_CURRENT; | ||
45 | ehdr->e_ident[EI_OSABI] = ELFOSABI_SYSV; | ||
46 | } | ||
47 | |||
48 | void InitElf32(uint32_t type) { | ||
49 | Elf32_Ehdr ehdr; | 45 | Elf32_Ehdr ehdr; |
46 | TestInitEhdr<Elf32_Ehdr>(&ehdr, ELFCLASS32, machine_type); | ||
50 | 47 | ||
51 | InitEhdr<Elf32_Ehdr>(&ehdr); | ||
52 | ehdr.e_ident[EI_CLASS] = ELFCLASS32; | ||
53 | |||
54 | ehdr.e_type = ET_DYN; | ||
55 | ehdr.e_machine = type; | ||
56 | ehdr.e_version = EV_CURRENT; | ||
57 | ehdr.e_entry = 0; | ||
58 | ehdr.e_phoff = 0x100; | 48 | ehdr.e_phoff = 0x100; |
59 | ehdr.e_shoff = 0; | ||
60 | ehdr.e_flags = 0; | ||
61 | ehdr.e_ehsize = sizeof(ehdr); | 49 | ehdr.e_ehsize = sizeof(ehdr); |
62 | ehdr.e_phentsize = sizeof(Elf32_Phdr); | 50 | ehdr.e_phentsize = sizeof(Elf32_Phdr); |
63 | ehdr.e_phnum = 1; | 51 | ehdr.e_phnum = 1; |
64 | ehdr.e_shentsize = sizeof(Elf32_Shdr); | 52 | ehdr.e_shentsize = sizeof(Elf32_Shdr); |
65 | ehdr.e_shnum = 0; | 53 | if (machine_type == EM_ARM) { |
66 | ehdr.e_shstrndx = 0; | ||
67 | if (type == EM_ARM) { | ||
68 | ehdr.e_flags = 0x5000200; | 54 | ehdr.e_flags = 0x5000200; |
69 | ehdr.e_phnum = 2; | 55 | ehdr.e_phnum = 2; |
70 | } | 56 | } |
@@ -73,16 +59,13 @@ class ElfTest : public ::testing::Test { | |||
73 | Elf32_Phdr phdr; | 59 | Elf32_Phdr phdr; |
74 | memset(&phdr, 0, sizeof(phdr)); | 60 | memset(&phdr, 0, sizeof(phdr)); |
75 | phdr.p_type = PT_LOAD; | 61 | phdr.p_type = PT_LOAD; |
76 | phdr.p_offset = 0; | ||
77 | phdr.p_vaddr = 0; | ||
78 | phdr.p_paddr = 0; | ||
79 | phdr.p_filesz = 0x10000; | 62 | phdr.p_filesz = 0x10000; |
80 | phdr.p_memsz = 0x10000; | 63 | phdr.p_memsz = 0x10000; |
81 | phdr.p_flags = PF_R | PF_X; | 64 | phdr.p_flags = PF_R | PF_X; |
82 | phdr.p_align = 0x1000; | 65 | phdr.p_align = 0x1000; |
83 | memory_->SetMemory(0x100, &phdr, sizeof(phdr)); | 66 | memory_->SetMemory(0x100, &phdr, sizeof(phdr)); |
84 | 67 | ||
85 | if (type == EM_ARM) { | 68 | if (machine_type == EM_ARM) { |
86 | memset(&phdr, 0, sizeof(phdr)); | 69 | memset(&phdr, 0, sizeof(phdr)); |
87 | phdr.p_type = PT_ARM_EXIDX; | 70 | phdr.p_type = PT_ARM_EXIDX; |
88 | phdr.p_offset = 0x30000; | 71 | phdr.p_offset = 0x30000; |
@@ -96,33 +79,21 @@ class ElfTest : public ::testing::Test { | |||
96 | } | 79 | } |
97 | } | 80 | } |
98 | 81 | ||
99 | void InitElf64(uint32_t type) { | 82 | void InitElf64(uint32_t machine_type) { |
100 | Elf64_Ehdr ehdr; | 83 | Elf64_Ehdr ehdr; |
84 | TestInitEhdr<Elf64_Ehdr>(&ehdr, ELFCLASS64, machine_type); | ||
101 | 85 | ||
102 | InitEhdr<Elf64_Ehdr>(&ehdr); | ||
103 | ehdr.e_ident[EI_CLASS] = ELFCLASS64; | ||
104 | |||
105 | ehdr.e_type = ET_DYN; | ||
106 | ehdr.e_machine = type; | ||
107 | ehdr.e_version = EV_CURRENT; | ||
108 | ehdr.e_entry = 0; | ||
109 | ehdr.e_phoff = 0x100; | 86 | ehdr.e_phoff = 0x100; |
110 | ehdr.e_shoff = 0; | ||
111 | ehdr.e_flags = 0x5000200; | 87 | ehdr.e_flags = 0x5000200; |
112 | ehdr.e_ehsize = sizeof(ehdr); | 88 | ehdr.e_ehsize = sizeof(ehdr); |
113 | ehdr.e_phentsize = sizeof(Elf64_Phdr); | 89 | ehdr.e_phentsize = sizeof(Elf64_Phdr); |
114 | ehdr.e_phnum = 1; | 90 | ehdr.e_phnum = 1; |
115 | ehdr.e_shentsize = sizeof(Elf64_Shdr); | 91 | ehdr.e_shentsize = sizeof(Elf64_Shdr); |
116 | ehdr.e_shnum = 0; | ||
117 | ehdr.e_shstrndx = 0; | ||
118 | memory_->SetMemory(0, &ehdr, sizeof(ehdr)); | 92 | memory_->SetMemory(0, &ehdr, sizeof(ehdr)); |
119 | 93 | ||
120 | Elf64_Phdr phdr; | 94 | Elf64_Phdr phdr; |
121 | memset(&phdr, 0, sizeof(phdr)); | 95 | memset(&phdr, 0, sizeof(phdr)); |
122 | phdr.p_type = PT_LOAD; | 96 | phdr.p_type = PT_LOAD; |
123 | phdr.p_offset = 0; | ||
124 | phdr.p_vaddr = 0; | ||
125 | phdr.p_paddr = 0; | ||
126 | phdr.p_filesz = 0x10000; | 97 | phdr.p_filesz = 0x10000; |
127 | phdr.p_memsz = 0x10000; | 98 | phdr.p_memsz = 0x10000; |
128 | phdr.p_flags = PF_R | PF_X; | 99 | phdr.p_flags = PF_R | PF_X; |
@@ -161,6 +132,32 @@ TEST_F(ElfTest, elf_invalid) { | |||
161 | ASSERT_FALSE(elf.Step(0, nullptr, nullptr)); | 132 | ASSERT_FALSE(elf.Step(0, nullptr, nullptr)); |
162 | } | 133 | } |
163 | 134 | ||
135 | TEST_F(ElfTest, elf32_invalid_machine) { | ||
136 | Elf elf(memory_); | ||
137 | |||
138 | InitElf32(EM_PPC); | ||
139 | |||
140 | ResetLogs(); | ||
141 | ASSERT_FALSE(elf.Init()); | ||
142 | |||
143 | ASSERT_EQ("", GetFakeLogBuf()); | ||
144 | ASSERT_EQ("4 unwind 32 bit elf that is neither arm nor x86: e_machine = 20\n\n", | ||
145 | GetFakeLogPrint()); | ||
146 | } | ||
147 | |||
148 | TEST_F(ElfTest, elf64_invalid_machine) { | ||
149 | Elf elf(memory_); | ||
150 | |||
151 | InitElf64(EM_PPC64); | ||
152 | |||
153 | ResetLogs(); | ||
154 | ASSERT_FALSE(elf.Init()); | ||
155 | |||
156 | ASSERT_EQ("", GetFakeLogBuf()); | ||
157 | ASSERT_EQ("4 unwind 64 bit elf that is neither aarch64 nor x86_64: e_machine = 21\n\n", | ||
158 | GetFakeLogPrint()); | ||
159 | } | ||
160 | |||
164 | TEST_F(ElfTest, elf_arm) { | 161 | TEST_F(ElfTest, elf_arm) { |
165 | Elf elf(memory_); | 162 | Elf elf(memory_); |
166 | 163 | ||
@@ -208,3 +205,95 @@ TEST_F(ElfTest, elf_x86_64) { | |||
208 | ASSERT_EQ(ELFCLASS64, elf.class_type()); | 205 | ASSERT_EQ(ELFCLASS64, elf.class_type()); |
209 | ASSERT_TRUE(elf.interface() != nullptr); | 206 | ASSERT_TRUE(elf.interface() != nullptr); |
210 | } | 207 | } |
208 | |||
209 | TEST_F(ElfTest, gnu_debugdata_init_fail32) { | ||
210 | TestInitGnuDebugdata<Elf32_Ehdr, Elf32_Shdr>(ELFCLASS32, EM_ARM, false, | ||
211 | [&](uint64_t offset, const void* ptr, size_t size) { | ||
212 | memory_->SetMemory(offset, ptr, size); | ||
213 | }); | ||
214 | |||
215 | Elf elf(memory_); | ||
216 | ASSERT_TRUE(elf.Init()); | ||
217 | ASSERT_TRUE(elf.interface() != nullptr); | ||
218 | ASSERT_TRUE(elf.gnu_debugdata_interface() == nullptr); | ||
219 | EXPECT_EQ(0x1acU, elf.interface()->gnu_debugdata_offset()); | ||
220 | EXPECT_EQ(0x100U, elf.interface()->gnu_debugdata_size()); | ||
221 | } | ||
222 | |||
223 | TEST_F(ElfTest, gnu_debugdata_init_fail64) { | ||
224 | TestInitGnuDebugdata<Elf64_Ehdr, Elf64_Shdr>(ELFCLASS64, EM_AARCH64, false, | ||
225 | [&](uint64_t offset, const void* ptr, size_t size) { | ||
226 | memory_->SetMemory(offset, ptr, size); | ||
227 | }); | ||
228 | |||
229 | Elf elf(memory_); | ||
230 | ASSERT_TRUE(elf.Init()); | ||
231 | ASSERT_TRUE(elf.interface() != nullptr); | ||
232 | ASSERT_TRUE(elf.gnu_debugdata_interface() == nullptr); | ||
233 | EXPECT_EQ(0x200U, elf.interface()->gnu_debugdata_offset()); | ||
234 | EXPECT_EQ(0x100U, elf.interface()->gnu_debugdata_size()); | ||
235 | } | ||
236 | |||
237 | TEST_F(ElfTest, gnu_debugdata_init32) { | ||
238 | TestInitGnuDebugdata<Elf32_Ehdr, Elf32_Shdr>(ELFCLASS32, EM_ARM, true, | ||
239 | [&](uint64_t offset, const void* ptr, size_t size) { | ||
240 | memory_->SetMemory(offset, ptr, size); | ||
241 | }); | ||
242 | |||
243 | Elf elf(memory_); | ||
244 | ASSERT_TRUE(elf.Init()); | ||
245 | ASSERT_TRUE(elf.interface() != nullptr); | ||
246 | ASSERT_TRUE(elf.gnu_debugdata_interface() == nullptr); | ||
247 | EXPECT_EQ(0x1acU, elf.interface()->gnu_debugdata_offset()); | ||
248 | EXPECT_EQ(0x8cU, elf.interface()->gnu_debugdata_size()); | ||
249 | |||
250 | elf.InitGnuDebugdata(); | ||
251 | ASSERT_TRUE(elf.gnu_debugdata_interface() != nullptr); | ||
252 | } | ||
253 | |||
254 | TEST_F(ElfTest, gnu_debugdata_init64) { | ||
255 | TestInitGnuDebugdata<Elf64_Ehdr, Elf64_Shdr>(ELFCLASS64, EM_AARCH64, true, | ||
256 | [&](uint64_t offset, const void* ptr, size_t size) { | ||
257 | memory_->SetMemory(offset, ptr, size); | ||
258 | }); | ||
259 | |||
260 | Elf elf(memory_); | ||
261 | ASSERT_TRUE(elf.Init()); | ||
262 | ASSERT_TRUE(elf.interface() != nullptr); | ||
263 | ASSERT_TRUE(elf.gnu_debugdata_interface() == nullptr); | ||
264 | EXPECT_EQ(0x200U, elf.interface()->gnu_debugdata_offset()); | ||
265 | EXPECT_EQ(0x90U, elf.interface()->gnu_debugdata_size()); | ||
266 | |||
267 | elf.InitGnuDebugdata(); | ||
268 | ASSERT_TRUE(elf.gnu_debugdata_interface() != nullptr); | ||
269 | } | ||
270 | |||
271 | class MockElf : public Elf { | ||
272 | public: | ||
273 | MockElf(Memory* memory) : Elf(memory) {} | ||
274 | virtual ~MockElf() = default; | ||
275 | |||
276 | void set_valid(bool valid) { valid_ = valid; } | ||
277 | void set_elf_interface(ElfInterface* interface) { interface_.reset(interface); } | ||
278 | }; | ||
279 | |||
280 | TEST_F(ElfTest, rel_pc) { | ||
281 | MockElf elf(memory_); | ||
282 | |||
283 | ElfInterface* interface = new ElfInterface32(memory_); | ||
284 | elf.set_elf_interface(interface); | ||
285 | |||
286 | elf.set_valid(true); | ||
287 | interface->set_load_bias(0); | ||
288 | MapInfo map_info{.start = 0x1000, .end = 0x2000}; | ||
289 | |||
290 | ASSERT_EQ(0x101U, elf.GetRelPc(0x1101, &map_info)); | ||
291 | |||
292 | interface->set_load_bias(0x3000); | ||
293 | ASSERT_EQ(0x3101U, elf.GetRelPc(0x1101, &map_info)); | ||
294 | |||
295 | elf.set_valid(false); | ||
296 | ASSERT_EQ(0x101U, elf.GetRelPc(0x1101, &map_info)); | ||
297 | } | ||
298 | |||
299 | } // namespace unwindstack | ||