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>
18 #include <errno.h>
19 #include <fcntl.h>
20 #include <signal.h>
21 #include <string.h>
22 #include <sys/mman.h>
23 #include <sys/ptrace.h>
24 #include <sys/types.h>
25 #include <unistd.h>
26
27 #include <string>
28 #include <vector>
29
30 #include <gtest/gtest.h>
31
32 #include "ElfTestUtils.h"
33
34 namespace unwindstack {
35
36 template <typename Ehdr>
TestInitEhdr(Ehdr * ehdr,uint32_t elf_class,uint32_t machine_type)37 void TestInitEhdr(Ehdr* ehdr, uint32_t elf_class, uint32_t machine_type) {
38 memset(ehdr, 0, sizeof(Ehdr));
39 memcpy(&ehdr->e_ident[0], ELFMAG, SELFMAG);
40 ehdr->e_ident[EI_DATA] = ELFDATA2LSB;
41 ehdr->e_ident[EI_VERSION] = EV_CURRENT;
42 ehdr->e_ident[EI_OSABI] = ELFOSABI_SYSV;
43 ehdr->e_ident[EI_CLASS] = elf_class;
44 ehdr->e_type = ET_DYN;
45 ehdr->e_machine = machine_type;
46 ehdr->e_version = EV_CURRENT;
47 ehdr->e_ehsize = sizeof(Ehdr);
48 }
49
TestGetFileDirectory()50 std::string TestGetFileDirectory() {
51 std::string exec(testing::internal::GetArgvs()[0]);
52 auto const value = exec.find_last_of('/');
53 if (value == std::string::npos) {
54 return "tests/files/";
55 }
56 return exec.substr(0, value + 1) + "tests/files/";
57 }
58
59 template <typename Ehdr, typename Shdr>
TestInitGnuDebugdata(uint32_t elf_class,uint32_t machine,bool init_gnu_debugdata,TestCopyFuncType copy_func)60 void TestInitGnuDebugdata(uint32_t elf_class, uint32_t machine, bool init_gnu_debugdata,
61 TestCopyFuncType copy_func) {
62 Ehdr ehdr;
63
64 TestInitEhdr(&ehdr, elf_class, machine);
65
66 uint64_t offset = sizeof(Ehdr);
67 ehdr.e_shoff = offset;
68 ehdr.e_shnum = 3;
69 ehdr.e_shentsize = sizeof(Shdr);
70 ehdr.e_shstrndx = 2;
71 copy_func(0, &ehdr, sizeof(ehdr));
72
73 Shdr shdr;
74 memset(&shdr, 0, sizeof(shdr));
75 shdr.sh_type = SHT_NULL;
76 copy_func(offset, &shdr, sizeof(shdr));
77 offset += ehdr.e_shentsize;
78
79 // Skip this header, it will contain the gnu_debugdata information.
80 uint64_t gnu_offset = offset;
81 offset += ehdr.e_shentsize;
82
83 uint64_t symtab_offset = sizeof(ehdr) + ehdr.e_shnum * ehdr.e_shentsize;
84 memset(&shdr, 0, sizeof(shdr));
85 shdr.sh_name = 1;
86 shdr.sh_type = SHT_STRTAB;
87 shdr.sh_offset = symtab_offset;
88 shdr.sh_size = 0x100;
89 copy_func(offset, &shdr, sizeof(shdr));
90
91 char value = '\0';
92 uint64_t symname_offset = symtab_offset;
93 copy_func(symname_offset, &value, 1);
94 symname_offset++;
95 std::string name(".shstrtab");
96 copy_func(symname_offset, name.c_str(), name.size() + 1);
97 symname_offset += name.size() + 1;
98 name = ".gnu_debugdata";
99 copy_func(symname_offset, name.c_str(), name.size() + 1);
100
101 ssize_t bytes = 0x100;
102 offset = symtab_offset + 0x100;
103 if (init_gnu_debugdata) {
104 // Read in the compressed elf data and copy it in.
105 name = TestGetFileDirectory();
106 if (elf_class == ELFCLASS32) {
107 name += "elf32.xz";
108 } else {
109 name += "elf64.xz";
110 }
111 int fd = TEMP_FAILURE_RETRY(open(name.c_str(), O_RDONLY));
112 ASSERT_NE(-1, fd) << "Cannot open " + name;
113 // Assumes the file is less than 1024 bytes.
114 std::vector<uint8_t> buf(1024);
115 bytes = TEMP_FAILURE_RETRY(read(fd, buf.data(), buf.size()));
116 ASSERT_GT(bytes, 0);
117 // Make sure the file isn't too big.
118 ASSERT_NE(static_cast<size_t>(bytes), buf.size())
119 << "File " + name + " is too big, increase buffer size.";
120 close(fd);
121 buf.resize(bytes);
122 copy_func(offset, buf.data(), buf.size());
123 }
124
125 memset(&shdr, 0, sizeof(shdr));
126 shdr.sh_type = SHT_PROGBITS;
127 shdr.sh_name = symname_offset - symtab_offset;
128 shdr.sh_addr = offset;
129 shdr.sh_offset = offset;
130 shdr.sh_size = bytes;
131 copy_func(gnu_offset, &shdr, sizeof(shdr));
132 }
133
134 template void TestInitEhdr<Elf32_Ehdr>(Elf32_Ehdr*, uint32_t, uint32_t);
135 template void TestInitEhdr<Elf64_Ehdr>(Elf64_Ehdr*, uint32_t, uint32_t);
136
137 template void TestInitGnuDebugdata<Elf32_Ehdr, Elf32_Shdr>(uint32_t, uint32_t, bool,
138 TestCopyFuncType);
139 template void TestInitGnuDebugdata<Elf64_Ehdr, Elf64_Shdr>(uint32_t, uint32_t, bool,
140 TestCopyFuncType);
141
142 } // namespace unwindstack
143