blob: 7d38ee0416d0217ffdeeeecec9135a0742802906 [file] [log] [blame]
Christopher Ferris3958f802017-02-01 15:44:40 -08001/*
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
Christopher Ferrisbae69f12017-06-28 14:51:54 -070023#include <7zCrc.h>
24#include <Xz.h>
25#include <XzCrc64.h>
26
Christopher Ferris61d40972017-06-12 19:14:20 -070027#include "DwarfDebugFrame.h"
28#include "DwarfEhFrame.h"
Christopher Ferris8098b1c2017-06-20 13:54:08 -070029#include "DwarfSection.h"
Christopher Ferris3958f802017-02-01 15:44:40 -080030#include "ElfInterface.h"
Christopher Ferris8098b1c2017-06-20 13:54:08 -070031#include "Log.h"
Christopher Ferris3958f802017-02-01 15:44:40 -080032#include "Memory.h"
33#include "Regs.h"
Christopher Ferris8098b1c2017-06-20 13:54:08 -070034#include "Symbols.h"
35
36ElfInterface::~ElfInterface() {
37 for (auto symbol : symbols_) {
38 delete symbol;
39 }
40}
Christopher Ferris3958f802017-02-01 15:44:40 -080041
Christopher Ferrisbae69f12017-06-28 14:51:54 -070042Memory* ElfInterface::CreateGnuDebugdataMemory() {
43 if (gnu_debugdata_offset_ == 0 || gnu_debugdata_size_ == 0) {
44 return nullptr;
45 }
46
47 // TODO: Only call these initialization functions once.
48 CrcGenerateTable();
49 Crc64GenerateTable();
50
51 std::vector<uint8_t> src(gnu_debugdata_size_);
52 if (!memory_->Read(gnu_debugdata_offset_, src.data(), gnu_debugdata_size_)) {
53 gnu_debugdata_offset_ = 0;
54 gnu_debugdata_size_ = static_cast<uint64_t>(-1);
55 return nullptr;
56 }
57
58 ISzAlloc alloc;
59 CXzUnpacker state;
60 alloc.Alloc = [](void*, size_t size) { return malloc(size); };
61 alloc.Free = [](void*, void* ptr) { return free(ptr); };
62
63 XzUnpacker_Construct(&state, &alloc);
64
65 std::unique_ptr<MemoryBuffer> dst(new MemoryBuffer);
66 int return_val;
67 size_t src_offset = 0;
68 size_t dst_offset = 0;
69 ECoderStatus status;
70 dst->Resize(5 * gnu_debugdata_size_);
71 do {
72 size_t src_remaining = src.size() - src_offset;
73 size_t dst_remaining = dst->Size() - dst_offset;
74 if (dst_remaining < 2 * gnu_debugdata_size_) {
75 dst->Resize(dst->Size() + 2 * gnu_debugdata_size_);
76 dst_remaining += 2 * gnu_debugdata_size_;
77 }
78 return_val = XzUnpacker_Code(&state, dst->GetPtr(dst_offset), &dst_remaining, &src[src_offset],
79 &src_remaining, CODER_FINISH_ANY, &status);
80 src_offset += src_remaining;
81 dst_offset += dst_remaining;
82 } while (return_val == SZ_OK && status == CODER_STATUS_NOT_FINISHED);
83 XzUnpacker_Free(&state);
84 if (return_val != SZ_OK || !XzUnpacker_IsStreamWasFinished(&state)) {
85 gnu_debugdata_offset_ = 0;
86 gnu_debugdata_size_ = static_cast<uint64_t>(-1);
87 return nullptr;
88 }
89
90 // Shrink back down to the exact size.
91 dst->Resize(dst_offset);
92
93 return dst.release();
94}
95
Christopher Ferris61d40972017-06-12 19:14:20 -070096template <typename AddressType>
97void ElfInterface::InitHeadersWithTemplate() {
98 if (eh_frame_offset_ != 0) {
99 eh_frame_.reset(new DwarfEhFrame<AddressType>(memory_));
100 if (!eh_frame_->Init(eh_frame_offset_, eh_frame_size_)) {
101 eh_frame_.reset(nullptr);
102 eh_frame_offset_ = 0;
103 eh_frame_size_ = static_cast<uint64_t>(-1);
104 }
105 }
106
107 if (debug_frame_offset_ != 0) {
108 debug_frame_.reset(new DwarfDebugFrame<AddressType>(memory_));
109 if (!debug_frame_->Init(debug_frame_offset_, debug_frame_size_)) {
110 debug_frame_.reset(nullptr);
111 debug_frame_offset_ = 0;
112 debug_frame_size_ = static_cast<uint64_t>(-1);
113 }
114 }
115}
116
Christopher Ferris3958f802017-02-01 15:44:40 -0800117template <typename EhdrType, typename PhdrType, typename ShdrType>
118bool ElfInterface::ReadAllHeaders() {
119 EhdrType ehdr;
120 if (!memory_->Read(0, &ehdr, sizeof(ehdr))) {
121 return false;
122 }
123
124 if (!ReadProgramHeaders<EhdrType, PhdrType>(ehdr)) {
125 return false;
126 }
Christopher Ferris8098b1c2017-06-20 13:54:08 -0700127
128 // We could still potentially unwind without the section header
129 // information, so ignore any errors.
130 if (!ReadSectionHeaders<EhdrType, ShdrType>(ehdr)) {
131 log(0, "Malformed section header found, ignoring...");
132 }
133 return true;
Christopher Ferris3958f802017-02-01 15:44:40 -0800134}
135
136template <typename EhdrType, typename PhdrType>
137bool ElfInterface::ReadProgramHeaders(const EhdrType& ehdr) {
138 uint64_t offset = ehdr.e_phoff;
139 for (size_t i = 0; i < ehdr.e_phnum; i++, offset += ehdr.e_phentsize) {
140 PhdrType phdr;
Christopher Ferrisf447c8e2017-04-03 12:39:47 -0700141 if (!memory_->ReadField(offset, &phdr, &phdr.p_type, sizeof(phdr.p_type))) {
Christopher Ferris3958f802017-02-01 15:44:40 -0800142 return false;
143 }
144
145 if (HandleType(offset, phdr.p_type)) {
146 continue;
147 }
148
149 switch (phdr.p_type) {
150 case PT_LOAD:
151 {
152 // Get the flags first, if this isn't an executable header, ignore it.
Christopher Ferrisf447c8e2017-04-03 12:39:47 -0700153 if (!memory_->ReadField(offset, &phdr, &phdr.p_flags, sizeof(phdr.p_flags))) {
Christopher Ferris3958f802017-02-01 15:44:40 -0800154 return false;
155 }
156 if ((phdr.p_flags & PF_X) == 0) {
157 continue;
158 }
159
Christopher Ferrisf447c8e2017-04-03 12:39:47 -0700160 if (!memory_->ReadField(offset, &phdr, &phdr.p_vaddr, sizeof(phdr.p_vaddr))) {
Christopher Ferris3958f802017-02-01 15:44:40 -0800161 return false;
162 }
Christopher Ferrisf447c8e2017-04-03 12:39:47 -0700163 if (!memory_->ReadField(offset, &phdr, &phdr.p_offset, sizeof(phdr.p_offset))) {
Christopher Ferris3958f802017-02-01 15:44:40 -0800164 return false;
165 }
Christopher Ferrisf447c8e2017-04-03 12:39:47 -0700166 if (!memory_->ReadField(offset, &phdr, &phdr.p_memsz, sizeof(phdr.p_memsz))) {
Christopher Ferris3958f802017-02-01 15:44:40 -0800167 return false;
168 }
169 pt_loads_[phdr.p_offset] = LoadInfo{phdr.p_offset, phdr.p_vaddr,
170 static_cast<size_t>(phdr.p_memsz)};
171 if (phdr.p_offset == 0) {
172 load_bias_ = phdr.p_vaddr;
173 }
174 break;
175 }
176
177 case PT_GNU_EH_FRAME:
Christopher Ferrisf447c8e2017-04-03 12:39:47 -0700178 if (!memory_->ReadField(offset, &phdr, &phdr.p_offset, sizeof(phdr.p_offset))) {
Christopher Ferris3958f802017-02-01 15:44:40 -0800179 return false;
180 }
181 eh_frame_offset_ = phdr.p_offset;
Christopher Ferrisf447c8e2017-04-03 12:39:47 -0700182 if (!memory_->ReadField(offset, &phdr, &phdr.p_memsz, sizeof(phdr.p_memsz))) {
Christopher Ferris3958f802017-02-01 15:44:40 -0800183 return false;
184 }
185 eh_frame_size_ = phdr.p_memsz;
186 break;
187
188 case PT_DYNAMIC:
Christopher Ferrisf447c8e2017-04-03 12:39:47 -0700189 if (!memory_->ReadField(offset, &phdr, &phdr.p_offset, sizeof(phdr.p_offset))) {
Christopher Ferris3958f802017-02-01 15:44:40 -0800190 return false;
191 }
192 dynamic_offset_ = phdr.p_offset;
Christopher Ferrisf447c8e2017-04-03 12:39:47 -0700193 if (!memory_->ReadField(offset, &phdr, &phdr.p_memsz, sizeof(phdr.p_memsz))) {
Christopher Ferris3958f802017-02-01 15:44:40 -0800194 return false;
195 }
196 dynamic_size_ = phdr.p_memsz;
197 break;
198 }
199 }
200 return true;
201}
202
203template <typename EhdrType, typename ShdrType>
204bool ElfInterface::ReadSectionHeaders(const EhdrType& ehdr) {
205 uint64_t offset = ehdr.e_shoff;
206 uint64_t sec_offset = 0;
207 uint64_t sec_size = 0;
208
209 // Get the location of the section header names.
210 // If something is malformed in the header table data, we aren't going
211 // to terminate, we'll simply ignore this part.
212 ShdrType shdr;
213 if (ehdr.e_shstrndx < ehdr.e_shnum) {
214 uint64_t sh_offset = offset + ehdr.e_shstrndx * ehdr.e_shentsize;
Christopher Ferrisf447c8e2017-04-03 12:39:47 -0700215 if (memory_->ReadField(sh_offset, &shdr, &shdr.sh_offset, sizeof(shdr.sh_offset)) &&
216 memory_->ReadField(sh_offset, &shdr, &shdr.sh_size, sizeof(shdr.sh_size))) {
Christopher Ferris3958f802017-02-01 15:44:40 -0800217 sec_offset = shdr.sh_offset;
218 sec_size = shdr.sh_size;
219 }
220 }
221
222 // Skip the first header, it's always going to be NULL.
Christopher Ferris8098b1c2017-06-20 13:54:08 -0700223 offset += ehdr.e_shentsize;
Christopher Ferris3958f802017-02-01 15:44:40 -0800224 for (size_t i = 1; i < ehdr.e_shnum; i++, offset += ehdr.e_shentsize) {
Christopher Ferrisf447c8e2017-04-03 12:39:47 -0700225 if (!memory_->ReadField(offset, &shdr, &shdr.sh_type, sizeof(shdr.sh_type))) {
Christopher Ferris3958f802017-02-01 15:44:40 -0800226 return false;
227 }
228
Christopher Ferris8098b1c2017-06-20 13:54:08 -0700229 if (shdr.sh_type == SHT_SYMTAB || shdr.sh_type == SHT_DYNSYM) {
230 if (!memory_->Read(offset, &shdr, sizeof(shdr))) {
231 return false;
232 }
233 // Need to go get the information about the section that contains
234 // the string terminated names.
235 ShdrType str_shdr;
236 if (shdr.sh_link >= ehdr.e_shnum) {
237 return false;
238 }
239 uint64_t str_offset = ehdr.e_shoff + shdr.sh_link * ehdr.e_shentsize;
240 if (!memory_->ReadField(str_offset, &str_shdr, &str_shdr.sh_type, sizeof(str_shdr.sh_type))) {
241 return false;
242 }
243 if (str_shdr.sh_type != SHT_STRTAB) {
244 return false;
245 }
246 if (!memory_->ReadField(str_offset, &str_shdr, &str_shdr.sh_offset,
247 sizeof(str_shdr.sh_offset))) {
248 return false;
249 }
250 if (!memory_->ReadField(str_offset, &str_shdr, &str_shdr.sh_size, sizeof(str_shdr.sh_size))) {
251 return false;
252 }
253 symbols_.push_back(new Symbols(shdr.sh_offset, shdr.sh_size, shdr.sh_entsize,
254 str_shdr.sh_offset, str_shdr.sh_size));
255 } else if (shdr.sh_type == SHT_PROGBITS && sec_size != 0) {
Christopher Ferris3958f802017-02-01 15:44:40 -0800256 // Look for the .debug_frame and .gnu_debugdata.
Christopher Ferrisf447c8e2017-04-03 12:39:47 -0700257 if (!memory_->ReadField(offset, &shdr, &shdr.sh_name, sizeof(shdr.sh_name))) {
Christopher Ferris3958f802017-02-01 15:44:40 -0800258 return false;
259 }
260 if (shdr.sh_name < sec_size) {
261 std::string name;
262 if (memory_->ReadString(sec_offset + shdr.sh_name, &name)) {
Christopher Ferris8098b1c2017-06-20 13:54:08 -0700263 uint64_t* offset_ptr = nullptr;
264 uint64_t* size_ptr = nullptr;
Christopher Ferris3958f802017-02-01 15:44:40 -0800265 if (name == ".debug_frame") {
Christopher Ferris8098b1c2017-06-20 13:54:08 -0700266 offset_ptr = &debug_frame_offset_;
267 size_ptr = &debug_frame_size_;
Christopher Ferris3958f802017-02-01 15:44:40 -0800268 } else if (name == ".gnu_debugdata") {
Christopher Ferris8098b1c2017-06-20 13:54:08 -0700269 offset_ptr = &gnu_debugdata_offset_;
270 size_ptr = &gnu_debugdata_size_;
271 }
272 if (offset_ptr != nullptr &&
273 memory_->ReadField(offset, &shdr, &shdr.sh_offset, sizeof(shdr.sh_offset)) &&
274 memory_->ReadField(offset, &shdr, &shdr.sh_size, sizeof(shdr.sh_size))) {
275 *offset_ptr = shdr.sh_offset;
276 *size_ptr = shdr.sh_size;
Christopher Ferris3958f802017-02-01 15:44:40 -0800277 }
278 }
279 }
280 }
281 }
282 return true;
283}
284
285template <typename DynType>
286bool ElfInterface::GetSonameWithTemplate(std::string* soname) {
287 if (soname_type_ == SONAME_INVALID) {
288 return false;
289 }
290 if (soname_type_ == SONAME_VALID) {
291 *soname = soname_;
292 return true;
293 }
294
295 soname_type_ = SONAME_INVALID;
296
297 uint64_t soname_offset = 0;
298 uint64_t strtab_offset = 0;
299 uint64_t strtab_size = 0;
300
301 // Find the soname location from the dynamic headers section.
302 DynType dyn;
303 uint64_t offset = dynamic_offset_;
304 uint64_t max_offset = offset + dynamic_size_;
305 for (uint64_t offset = dynamic_offset_; offset < max_offset; offset += sizeof(DynType)) {
306 if (!memory_->Read(offset, &dyn, sizeof(dyn))) {
307 return false;
308 }
309
310 if (dyn.d_tag == DT_STRTAB) {
311 strtab_offset = dyn.d_un.d_ptr;
312 } else if (dyn.d_tag == DT_STRSZ) {
313 strtab_size = dyn.d_un.d_val;
314 } else if (dyn.d_tag == DT_SONAME) {
315 soname_offset = dyn.d_un.d_val;
316 } else if (dyn.d_tag == DT_NULL) {
317 break;
318 }
319 }
320
321 soname_offset += strtab_offset;
322 if (soname_offset >= strtab_offset + strtab_size) {
323 return false;
324 }
325 if (!memory_->ReadString(soname_offset, &soname_)) {
326 return false;
327 }
328 soname_type_ = SONAME_VALID;
329 *soname = soname_;
330 return true;
331}
332
Christopher Ferris8098b1c2017-06-20 13:54:08 -0700333template <typename SymType>
334bool ElfInterface::GetFunctionNameWithTemplate(uint64_t addr, std::string* name,
335 uint64_t* func_offset) {
336 if (symbols_.empty()) {
337 return false;
338 }
339
340 for (const auto symbol : symbols_) {
341 if (symbol->GetName<SymType>(addr, load_bias_, memory_, name, func_offset)) {
342 return true;
343 }
344 }
345 return false;
346}
347
348bool ElfInterface::Step(uint64_t pc, Regs* regs, Memory* process_memory) {
349 // Need to subtract off the load_bias to get the correct pc.
350 if (pc < load_bias_) {
351 return false;
352 }
353 pc -= load_bias_;
354
355 // Try the eh_frame first.
356 DwarfSection* eh_frame = eh_frame_.get();
357 if (eh_frame != nullptr && eh_frame->Step(pc, regs, process_memory)) {
358 return true;
359 }
360
361 // Try the debug_frame next.
362 DwarfSection* debug_frame = debug_frame_.get();
363 if (debug_frame != nullptr && debug_frame->Step(pc, regs, process_memory)) {
364 return true;
365 }
366
Christopher Ferris3958f802017-02-01 15:44:40 -0800367 return false;
368}
369
370// Instantiate all of the needed template functions.
Christopher Ferris61d40972017-06-12 19:14:20 -0700371template void ElfInterface::InitHeadersWithTemplate<uint32_t>();
372template void ElfInterface::InitHeadersWithTemplate<uint64_t>();
373
Christopher Ferris3958f802017-02-01 15:44:40 -0800374template bool ElfInterface::ReadAllHeaders<Elf32_Ehdr, Elf32_Phdr, Elf32_Shdr>();
375template bool ElfInterface::ReadAllHeaders<Elf64_Ehdr, Elf64_Phdr, Elf64_Shdr>();
376
377template bool ElfInterface::ReadProgramHeaders<Elf32_Ehdr, Elf32_Phdr>(const Elf32_Ehdr&);
378template bool ElfInterface::ReadProgramHeaders<Elf64_Ehdr, Elf64_Phdr>(const Elf64_Ehdr&);
379
380template bool ElfInterface::ReadSectionHeaders<Elf32_Ehdr, Elf32_Shdr>(const Elf32_Ehdr&);
381template bool ElfInterface::ReadSectionHeaders<Elf64_Ehdr, Elf64_Shdr>(const Elf64_Ehdr&);
382
383template bool ElfInterface::GetSonameWithTemplate<Elf32_Dyn>(std::string*);
384template bool ElfInterface::GetSonameWithTemplate<Elf64_Dyn>(std::string*);
Christopher Ferris8098b1c2017-06-20 13:54:08 -0700385
386template bool ElfInterface::GetFunctionNameWithTemplate<Elf32_Sym>(uint64_t, std::string*,
387 uint64_t*);
388template bool ElfInterface::GetFunctionNameWithTemplate<Elf64_Sym>(uint64_t, std::string*,
389 uint64_t*);