1 /*
2 * Copyright (C) 2017 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 <stdint.h>
19
20 #include <memory>
21 #include <string>
22
23 #include "ElfInterface.h"
24 #include "Memory.h"
25 #include "Regs.h"
26
27 template <typename EhdrType, typename PhdrType, typename ShdrType>
ReadAllHeaders()28 bool ElfInterface::ReadAllHeaders() {
29 EhdrType ehdr;
30 if (!memory_->Read(0, &ehdr, sizeof(ehdr))) {
31 return false;
32 }
33
34 if (!ReadProgramHeaders<EhdrType, PhdrType>(ehdr)) {
35 return false;
36 }
37 return ReadSectionHeaders<EhdrType, ShdrType>(ehdr);
38 }
39
40 template <typename EhdrType, typename PhdrType>
ReadProgramHeaders(const EhdrType & ehdr)41 bool ElfInterface::ReadProgramHeaders(const EhdrType& ehdr) {
42 uint64_t offset = ehdr.e_phoff;
43 for (size_t i = 0; i < ehdr.e_phnum; i++, offset += ehdr.e_phentsize) {
44 PhdrType phdr;
45 if (!memory_->Read(offset, &phdr, &phdr.p_type, sizeof(phdr.p_type))) {
46 return false;
47 }
48
49 if (HandleType(offset, phdr.p_type)) {
50 continue;
51 }
52
53 switch (phdr.p_type) {
54 case PT_LOAD:
55 {
56 // Get the flags first, if this isn't an executable header, ignore it.
57 if (!memory_->Read(offset, &phdr, &phdr.p_flags, sizeof(phdr.p_flags))) {
58 return false;
59 }
60 if ((phdr.p_flags & PF_X) == 0) {
61 continue;
62 }
63
64 if (!memory_->Read(offset, &phdr, &phdr.p_vaddr, sizeof(phdr.p_vaddr))) {
65 return false;
66 }
67 if (!memory_->Read(offset, &phdr, &phdr.p_offset, sizeof(phdr.p_offset))) {
68 return false;
69 }
70 if (!memory_->Read(offset, &phdr, &phdr.p_memsz, sizeof(phdr.p_memsz))) {
71 return false;
72 }
73 pt_loads_[phdr.p_offset] = LoadInfo{phdr.p_offset, phdr.p_vaddr,
74 static_cast<size_t>(phdr.p_memsz)};
75 if (phdr.p_offset == 0) {
76 load_bias_ = phdr.p_vaddr;
77 }
78 break;
79 }
80
81 case PT_GNU_EH_FRAME:
82 if (!memory_->Read(offset, &phdr, &phdr.p_offset, sizeof(phdr.p_offset))) {
83 return false;
84 }
85 eh_frame_offset_ = phdr.p_offset;
86 if (!memory_->Read(offset, &phdr, &phdr.p_memsz, sizeof(phdr.p_memsz))) {
87 return false;
88 }
89 eh_frame_size_ = phdr.p_memsz;
90 break;
91
92 case PT_DYNAMIC:
93 if (!memory_->Read(offset, &phdr, &phdr.p_offset, sizeof(phdr.p_offset))) {
94 return false;
95 }
96 dynamic_offset_ = phdr.p_offset;
97 if (!memory_->Read(offset, &phdr, &phdr.p_memsz, sizeof(phdr.p_memsz))) {
98 return false;
99 }
100 dynamic_size_ = phdr.p_memsz;
101 break;
102 }
103 }
104 return true;
105 }
106
107 template <typename EhdrType, typename ShdrType>
ReadSectionHeaders(const EhdrType & ehdr)108 bool ElfInterface::ReadSectionHeaders(const EhdrType& ehdr) {
109 uint64_t offset = ehdr.e_shoff;
110 uint64_t sec_offset = 0;
111 uint64_t sec_size = 0;
112
113 // Get the location of the section header names.
114 // If something is malformed in the header table data, we aren't going
115 // to terminate, we'll simply ignore this part.
116 ShdrType shdr;
117 if (ehdr.e_shstrndx < ehdr.e_shnum) {
118 uint64_t sh_offset = offset + ehdr.e_shstrndx * ehdr.e_shentsize;
119 if (memory_->Read(sh_offset, &shdr, &shdr.sh_offset, sizeof(shdr.sh_offset))
120 && memory_->Read(sh_offset, &shdr, &shdr.sh_size, sizeof(shdr.sh_size))) {
121 sec_offset = shdr.sh_offset;
122 sec_size = shdr.sh_size;
123 }
124 }
125
126 // Skip the first header, it's always going to be NULL.
127 for (size_t i = 1; i < ehdr.e_shnum; i++, offset += ehdr.e_shentsize) {
128 if (!memory_->Read(offset, &shdr, &shdr.sh_type, sizeof(shdr.sh_type))) {
129 return false;
130 }
131
132 if (shdr.sh_type == SHT_PROGBITS) {
133 // Look for the .debug_frame and .gnu_debugdata.
134 if (!memory_->Read(offset, &shdr, &shdr.sh_name, sizeof(shdr.sh_name))) {
135 return false;
136 }
137 if (shdr.sh_name < sec_size) {
138 std::string name;
139 if (memory_->ReadString(sec_offset + shdr.sh_name, &name)) {
140 if (name == ".debug_frame") {
141 if (memory_->Read(offset, &shdr, &shdr.sh_offset, sizeof(shdr.sh_offset))
142 && memory_->Read(offset, &shdr, &shdr.sh_size, sizeof(shdr.sh_size))) {
143 debug_frame_offset_ = shdr.sh_offset;
144 debug_frame_size_ = shdr.sh_size;
145 }
146 } else if (name == ".gnu_debugdata") {
147 if (memory_->Read(offset, &shdr, &shdr.sh_offset, sizeof(shdr.sh_offset))
148 && memory_->Read(offset, &shdr, &shdr.sh_size, sizeof(shdr.sh_size))) {
149 gnu_debugdata_offset_ = shdr.sh_offset;
150 gnu_debugdata_size_ = shdr.sh_size;
151 }
152 }
153 }
154 }
155 }
156 }
157 return true;
158 }
159
160 template <typename DynType>
GetSonameWithTemplate(std::string * soname)161 bool ElfInterface::GetSonameWithTemplate(std::string* soname) {
162 if (soname_type_ == SONAME_INVALID) {
163 return false;
164 }
165 if (soname_type_ == SONAME_VALID) {
166 *soname = soname_;
167 return true;
168 }
169
170 soname_type_ = SONAME_INVALID;
171
172 uint64_t soname_offset = 0;
173 uint64_t strtab_offset = 0;
174 uint64_t strtab_size = 0;
175
176 // Find the soname location from the dynamic headers section.
177 DynType dyn;
178 uint64_t offset = dynamic_offset_;
179 uint64_t max_offset = offset + dynamic_size_;
180 for (uint64_t offset = dynamic_offset_; offset < max_offset; offset += sizeof(DynType)) {
181 if (!memory_->Read(offset, &dyn, sizeof(dyn))) {
182 return false;
183 }
184
185 if (dyn.d_tag == DT_STRTAB) {
186 strtab_offset = dyn.d_un.d_ptr;
187 } else if (dyn.d_tag == DT_STRSZ) {
188 strtab_size = dyn.d_un.d_val;
189 } else if (dyn.d_tag == DT_SONAME) {
190 soname_offset = dyn.d_un.d_val;
191 } else if (dyn.d_tag == DT_NULL) {
192 break;
193 }
194 }
195
196 soname_offset += strtab_offset;
197 if (soname_offset >= strtab_offset + strtab_size) {
198 return false;
199 }
200 if (!memory_->ReadString(soname_offset, &soname_)) {
201 return false;
202 }
203 soname_type_ = SONAME_VALID;
204 *soname = soname_;
205 return true;
206 }
207
Step(uint64_t,Regs *,Memory *)208 bool ElfInterface::Step(uint64_t, Regs*, Memory*) {
209 return false;
210 }
211
212 // Instantiate all of the needed template functions.
213 template bool ElfInterface::ReadAllHeaders<Elf32_Ehdr, Elf32_Phdr, Elf32_Shdr>();
214 template bool ElfInterface::ReadAllHeaders<Elf64_Ehdr, Elf64_Phdr, Elf64_Shdr>();
215
216 template bool ElfInterface::ReadProgramHeaders<Elf32_Ehdr, Elf32_Phdr>(const Elf32_Ehdr&);
217 template bool ElfInterface::ReadProgramHeaders<Elf64_Ehdr, Elf64_Phdr>(const Elf64_Ehdr&);
218
219 template bool ElfInterface::ReadSectionHeaders<Elf32_Ehdr, Elf32_Shdr>(const Elf32_Ehdr&);
220 template bool ElfInterface::ReadSectionHeaders<Elf64_Ehdr, Elf64_Shdr>(const Elf64_Ehdr&);
221
222 template bool ElfInterface::GetSonameWithTemplate<Elf32_Dyn>(std::string*);
223 template bool ElfInterface::GetSonameWithTemplate<Elf64_Dyn>(std::string*);
224