blob: 20cc1b06cf51efc98ee6026203c58f1da51f7829 [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 Ferrisd226a512017-07-14 10:37:19 -070027#include <unwindstack/DwarfSection.h>
28#include <unwindstack/ElfInterface.h>
29#include <unwindstack/Log.h>
30#include <unwindstack/Memory.h>
31#include <unwindstack/Regs.h>
32
Christopher Ferris61d40972017-06-12 19:14:20 -070033#include "DwarfDebugFrame.h"
34#include "DwarfEhFrame.h"
Christopher Ferris8098b1c2017-06-20 13:54:08 -070035#include "Symbols.h"
36
Christopher Ferrisd226a512017-07-14 10:37:19 -070037namespace unwindstack {
38
Christopher Ferris8098b1c2017-06-20 13:54:08 -070039ElfInterface::~ElfInterface() {
40 for (auto symbol : symbols_) {
41 delete symbol;
42 }
43}
Christopher Ferris3958f802017-02-01 15:44:40 -080044
Christopher Ferrisbae69f12017-06-28 14:51:54 -070045Memory* ElfInterface::CreateGnuDebugdataMemory() {
46 if (gnu_debugdata_offset_ == 0 || gnu_debugdata_size_ == 0) {
47 return nullptr;
48 }
49
50 // TODO: Only call these initialization functions once.
51 CrcGenerateTable();
52 Crc64GenerateTable();
53
54 std::vector<uint8_t> src(gnu_debugdata_size_);
55 if (!memory_->Read(gnu_debugdata_offset_, src.data(), gnu_debugdata_size_)) {
56 gnu_debugdata_offset_ = 0;
57 gnu_debugdata_size_ = static_cast<uint64_t>(-1);
58 return nullptr;
59 }
60
61 ISzAlloc alloc;
62 CXzUnpacker state;
63 alloc.Alloc = [](void*, size_t size) { return malloc(size); };
64 alloc.Free = [](void*, void* ptr) { return free(ptr); };
65
66 XzUnpacker_Construct(&state, &alloc);
67
68 std::unique_ptr<MemoryBuffer> dst(new MemoryBuffer);
69 int return_val;
70 size_t src_offset = 0;
71 size_t dst_offset = 0;
72 ECoderStatus status;
73 dst->Resize(5 * gnu_debugdata_size_);
74 do {
75 size_t src_remaining = src.size() - src_offset;
76 size_t dst_remaining = dst->Size() - dst_offset;
77 if (dst_remaining < 2 * gnu_debugdata_size_) {
78 dst->Resize(dst->Size() + 2 * gnu_debugdata_size_);
79 dst_remaining += 2 * gnu_debugdata_size_;
80 }
81 return_val = XzUnpacker_Code(&state, dst->GetPtr(dst_offset), &dst_remaining, &src[src_offset],
82 &src_remaining, CODER_FINISH_ANY, &status);
83 src_offset += src_remaining;
84 dst_offset += dst_remaining;
85 } while (return_val == SZ_OK && status == CODER_STATUS_NOT_FINISHED);
86 XzUnpacker_Free(&state);
87 if (return_val != SZ_OK || !XzUnpacker_IsStreamWasFinished(&state)) {
88 gnu_debugdata_offset_ = 0;
89 gnu_debugdata_size_ = static_cast<uint64_t>(-1);
90 return nullptr;
91 }
92
93 // Shrink back down to the exact size.
94 dst->Resize(dst_offset);
95
96 return dst.release();
97}
98
Christopher Ferris61d40972017-06-12 19:14:20 -070099template <typename AddressType>
100void ElfInterface::InitHeadersWithTemplate() {
101 if (eh_frame_offset_ != 0) {
102 eh_frame_.reset(new DwarfEhFrame<AddressType>(memory_));
103 if (!eh_frame_->Init(eh_frame_offset_, eh_frame_size_)) {
104 eh_frame_.reset(nullptr);
105 eh_frame_offset_ = 0;
106 eh_frame_size_ = static_cast<uint64_t>(-1);
107 }
108 }
109
110 if (debug_frame_offset_ != 0) {
111 debug_frame_.reset(new DwarfDebugFrame<AddressType>(memory_));
112 if (!debug_frame_->Init(debug_frame_offset_, debug_frame_size_)) {
113 debug_frame_.reset(nullptr);
114 debug_frame_offset_ = 0;
115 debug_frame_size_ = static_cast<uint64_t>(-1);
116 }
117 }
118}
119
Christopher Ferris3958f802017-02-01 15:44:40 -0800120template <typename EhdrType, typename PhdrType, typename ShdrType>
Christopher Ferrise69f4702017-10-19 16:08:58 -0700121bool ElfInterface::ReadAllHeaders(uint64_t* load_bias) {
Christopher Ferris3958f802017-02-01 15:44:40 -0800122 EhdrType ehdr;
123 if (!memory_->Read(0, &ehdr, sizeof(ehdr))) {
124 return false;
125 }
126
Christopher Ferrise69f4702017-10-19 16:08:58 -0700127 if (!ReadProgramHeaders<EhdrType, PhdrType>(ehdr, load_bias)) {
Christopher Ferris3958f802017-02-01 15:44:40 -0800128 return false;
129 }
Christopher Ferris8098b1c2017-06-20 13:54:08 -0700130
131 // We could still potentially unwind without the section header
132 // information, so ignore any errors.
133 if (!ReadSectionHeaders<EhdrType, ShdrType>(ehdr)) {
134 log(0, "Malformed section header found, ignoring...");
135 }
136 return true;
Christopher Ferris3958f802017-02-01 15:44:40 -0800137}
138
139template <typename EhdrType, typename PhdrType>
Christopher Ferrise69f4702017-10-19 16:08:58 -0700140bool ElfInterface::ReadProgramHeaders(const EhdrType& ehdr, uint64_t* load_bias) {
Christopher Ferris3958f802017-02-01 15:44:40 -0800141 uint64_t offset = ehdr.e_phoff;
142 for (size_t i = 0; i < ehdr.e_phnum; i++, offset += ehdr.e_phentsize) {
143 PhdrType phdr;
Christopher Ferrisf447c8e2017-04-03 12:39:47 -0700144 if (!memory_->ReadField(offset, &phdr, &phdr.p_type, sizeof(phdr.p_type))) {
Christopher Ferris3958f802017-02-01 15:44:40 -0800145 return false;
146 }
147
Christopher Ferrise69f4702017-10-19 16:08:58 -0700148 if (HandleType(offset, phdr.p_type, *load_bias)) {
Christopher Ferris3958f802017-02-01 15:44:40 -0800149 continue;
150 }
151
152 switch (phdr.p_type) {
153 case PT_LOAD:
154 {
155 // Get the flags first, if this isn't an executable header, ignore it.
Christopher Ferrisf447c8e2017-04-03 12:39:47 -0700156 if (!memory_->ReadField(offset, &phdr, &phdr.p_flags, sizeof(phdr.p_flags))) {
Christopher Ferris3958f802017-02-01 15:44:40 -0800157 return false;
158 }
159 if ((phdr.p_flags & PF_X) == 0) {
160 continue;
161 }
162
Christopher Ferrisf447c8e2017-04-03 12:39:47 -0700163 if (!memory_->ReadField(offset, &phdr, &phdr.p_vaddr, sizeof(phdr.p_vaddr))) {
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_offset, sizeof(phdr.p_offset))) {
Christopher Ferris3958f802017-02-01 15:44:40 -0800167 return false;
168 }
Christopher Ferrisf447c8e2017-04-03 12:39:47 -0700169 if (!memory_->ReadField(offset, &phdr, &phdr.p_memsz, sizeof(phdr.p_memsz))) {
Christopher Ferris3958f802017-02-01 15:44:40 -0800170 return false;
171 }
172 pt_loads_[phdr.p_offset] = LoadInfo{phdr.p_offset, phdr.p_vaddr,
173 static_cast<size_t>(phdr.p_memsz)};
174 if (phdr.p_offset == 0) {
Christopher Ferrise69f4702017-10-19 16:08:58 -0700175 *load_bias = phdr.p_vaddr;
Christopher Ferris3958f802017-02-01 15:44:40 -0800176 }
177 break;
178 }
179
180 case PT_GNU_EH_FRAME:
Christopher Ferrisf447c8e2017-04-03 12:39:47 -0700181 if (!memory_->ReadField(offset, &phdr, &phdr.p_offset, sizeof(phdr.p_offset))) {
Christopher Ferris3958f802017-02-01 15:44:40 -0800182 return false;
183 }
184 eh_frame_offset_ = phdr.p_offset;
Christopher Ferrisf447c8e2017-04-03 12:39:47 -0700185 if (!memory_->ReadField(offset, &phdr, &phdr.p_memsz, sizeof(phdr.p_memsz))) {
Christopher Ferris3958f802017-02-01 15:44:40 -0800186 return false;
187 }
188 eh_frame_size_ = phdr.p_memsz;
189 break;
190
191 case PT_DYNAMIC:
Christopher Ferrisf447c8e2017-04-03 12:39:47 -0700192 if (!memory_->ReadField(offset, &phdr, &phdr.p_offset, sizeof(phdr.p_offset))) {
Christopher Ferris3958f802017-02-01 15:44:40 -0800193 return false;
194 }
195 dynamic_offset_ = phdr.p_offset;
Christopher Ferrisf447c8e2017-04-03 12:39:47 -0700196 if (!memory_->ReadField(offset, &phdr, &phdr.p_memsz, sizeof(phdr.p_memsz))) {
Christopher Ferris3958f802017-02-01 15:44:40 -0800197 return false;
198 }
199 dynamic_size_ = phdr.p_memsz;
200 break;
201 }
202 }
203 return true;
204}
205
206template <typename EhdrType, typename ShdrType>
207bool ElfInterface::ReadSectionHeaders(const EhdrType& ehdr) {
208 uint64_t offset = ehdr.e_shoff;
209 uint64_t sec_offset = 0;
210 uint64_t sec_size = 0;
211
212 // Get the location of the section header names.
213 // If something is malformed in the header table data, we aren't going
214 // to terminate, we'll simply ignore this part.
215 ShdrType shdr;
216 if (ehdr.e_shstrndx < ehdr.e_shnum) {
217 uint64_t sh_offset = offset + ehdr.e_shstrndx * ehdr.e_shentsize;
Christopher Ferrisf447c8e2017-04-03 12:39:47 -0700218 if (memory_->ReadField(sh_offset, &shdr, &shdr.sh_offset, sizeof(shdr.sh_offset)) &&
219 memory_->ReadField(sh_offset, &shdr, &shdr.sh_size, sizeof(shdr.sh_size))) {
Christopher Ferris3958f802017-02-01 15:44:40 -0800220 sec_offset = shdr.sh_offset;
221 sec_size = shdr.sh_size;
222 }
223 }
224
225 // Skip the first header, it's always going to be NULL.
Christopher Ferris8098b1c2017-06-20 13:54:08 -0700226 offset += ehdr.e_shentsize;
Christopher Ferris3958f802017-02-01 15:44:40 -0800227 for (size_t i = 1; i < ehdr.e_shnum; i++, offset += ehdr.e_shentsize) {
Christopher Ferrisf447c8e2017-04-03 12:39:47 -0700228 if (!memory_->ReadField(offset, &shdr, &shdr.sh_type, sizeof(shdr.sh_type))) {
Christopher Ferris3958f802017-02-01 15:44:40 -0800229 return false;
230 }
231
Christopher Ferris8098b1c2017-06-20 13:54:08 -0700232 if (shdr.sh_type == SHT_SYMTAB || shdr.sh_type == SHT_DYNSYM) {
233 if (!memory_->Read(offset, &shdr, sizeof(shdr))) {
234 return false;
235 }
236 // Need to go get the information about the section that contains
237 // the string terminated names.
238 ShdrType str_shdr;
239 if (shdr.sh_link >= ehdr.e_shnum) {
240 return false;
241 }
242 uint64_t str_offset = ehdr.e_shoff + shdr.sh_link * ehdr.e_shentsize;
243 if (!memory_->ReadField(str_offset, &str_shdr, &str_shdr.sh_type, sizeof(str_shdr.sh_type))) {
244 return false;
245 }
246 if (str_shdr.sh_type != SHT_STRTAB) {
247 return false;
248 }
249 if (!memory_->ReadField(str_offset, &str_shdr, &str_shdr.sh_offset,
250 sizeof(str_shdr.sh_offset))) {
251 return false;
252 }
253 if (!memory_->ReadField(str_offset, &str_shdr, &str_shdr.sh_size, sizeof(str_shdr.sh_size))) {
254 return false;
255 }
256 symbols_.push_back(new Symbols(shdr.sh_offset, shdr.sh_size, shdr.sh_entsize,
257 str_shdr.sh_offset, str_shdr.sh_size));
258 } else if (shdr.sh_type == SHT_PROGBITS && sec_size != 0) {
Christopher Ferris3958f802017-02-01 15:44:40 -0800259 // Look for the .debug_frame and .gnu_debugdata.
Christopher Ferrisf447c8e2017-04-03 12:39:47 -0700260 if (!memory_->ReadField(offset, &shdr, &shdr.sh_name, sizeof(shdr.sh_name))) {
Christopher Ferris3958f802017-02-01 15:44:40 -0800261 return false;
262 }
263 if (shdr.sh_name < sec_size) {
264 std::string name;
265 if (memory_->ReadString(sec_offset + shdr.sh_name, &name)) {
Christopher Ferris8098b1c2017-06-20 13:54:08 -0700266 uint64_t* offset_ptr = nullptr;
267 uint64_t* size_ptr = nullptr;
Christopher Ferris3958f802017-02-01 15:44:40 -0800268 if (name == ".debug_frame") {
Christopher Ferris8098b1c2017-06-20 13:54:08 -0700269 offset_ptr = &debug_frame_offset_;
270 size_ptr = &debug_frame_size_;
Christopher Ferris3958f802017-02-01 15:44:40 -0800271 } else if (name == ".gnu_debugdata") {
Christopher Ferris8098b1c2017-06-20 13:54:08 -0700272 offset_ptr = &gnu_debugdata_offset_;
273 size_ptr = &gnu_debugdata_size_;
274 }
275 if (offset_ptr != nullptr &&
276 memory_->ReadField(offset, &shdr, &shdr.sh_offset, sizeof(shdr.sh_offset)) &&
277 memory_->ReadField(offset, &shdr, &shdr.sh_size, sizeof(shdr.sh_size))) {
278 *offset_ptr = shdr.sh_offset;
279 *size_ptr = shdr.sh_size;
Christopher Ferris3958f802017-02-01 15:44:40 -0800280 }
281 }
282 }
283 }
284 }
285 return true;
286}
287
288template <typename DynType>
289bool ElfInterface::GetSonameWithTemplate(std::string* soname) {
290 if (soname_type_ == SONAME_INVALID) {
291 return false;
292 }
293 if (soname_type_ == SONAME_VALID) {
294 *soname = soname_;
295 return true;
296 }
297
298 soname_type_ = SONAME_INVALID;
299
300 uint64_t soname_offset = 0;
301 uint64_t strtab_offset = 0;
302 uint64_t strtab_size = 0;
303
304 // Find the soname location from the dynamic headers section.
305 DynType dyn;
306 uint64_t offset = dynamic_offset_;
307 uint64_t max_offset = offset + dynamic_size_;
308 for (uint64_t offset = dynamic_offset_; offset < max_offset; offset += sizeof(DynType)) {
309 if (!memory_->Read(offset, &dyn, sizeof(dyn))) {
310 return false;
311 }
312
313 if (dyn.d_tag == DT_STRTAB) {
314 strtab_offset = dyn.d_un.d_ptr;
315 } else if (dyn.d_tag == DT_STRSZ) {
316 strtab_size = dyn.d_un.d_val;
317 } else if (dyn.d_tag == DT_SONAME) {
318 soname_offset = dyn.d_un.d_val;
319 } else if (dyn.d_tag == DT_NULL) {
320 break;
321 }
322 }
323
324 soname_offset += strtab_offset;
325 if (soname_offset >= strtab_offset + strtab_size) {
326 return false;
327 }
328 if (!memory_->ReadString(soname_offset, &soname_)) {
329 return false;
330 }
331 soname_type_ = SONAME_VALID;
332 *soname = soname_;
333 return true;
334}
335
Christopher Ferris8098b1c2017-06-20 13:54:08 -0700336template <typename SymType>
Christopher Ferrise69f4702017-10-19 16:08:58 -0700337bool ElfInterface::GetFunctionNameWithTemplate(uint64_t addr, uint64_t load_bias, std::string* name,
Christopher Ferris8098b1c2017-06-20 13:54:08 -0700338 uint64_t* func_offset) {
339 if (symbols_.empty()) {
340 return false;
341 }
342
343 for (const auto symbol : symbols_) {
Christopher Ferrise69f4702017-10-19 16:08:58 -0700344 if (symbol->GetName<SymType>(addr, load_bias, memory_, name, func_offset)) {
Christopher Ferris8098b1c2017-06-20 13:54:08 -0700345 return true;
346 }
347 }
348 return false;
349}
350
Christopher Ferrisb9de87f2017-09-20 13:37:24 -0700351bool ElfInterface::Step(uint64_t pc, Regs* regs, Memory* process_memory, bool* finished) {
Christopher Ferris8098b1c2017-06-20 13:54:08 -0700352 // Try the eh_frame first.
353 DwarfSection* eh_frame = eh_frame_.get();
Christopher Ferrisb9de87f2017-09-20 13:37:24 -0700354 if (eh_frame != nullptr && eh_frame->Step(pc, regs, process_memory, finished)) {
Christopher Ferris8098b1c2017-06-20 13:54:08 -0700355 return true;
356 }
357
358 // Try the debug_frame next.
359 DwarfSection* debug_frame = debug_frame_.get();
Christopher Ferrisb9de87f2017-09-20 13:37:24 -0700360 if (debug_frame != nullptr && debug_frame->Step(pc, regs, process_memory, finished)) {
Christopher Ferris8098b1c2017-06-20 13:54:08 -0700361 return true;
362 }
Christopher Ferris3958f802017-02-01 15:44:40 -0800363 return false;
364}
365
Christopher Ferris3f805ac2017-08-30 13:15:19 -0700366// This is an estimation of the size of the elf file using the location
367// of the section headers and size. This assumes that the section headers
368// are at the end of the elf file. If the elf has a load bias, the size
369// will be too large, but this is acceptable.
370template <typename EhdrType>
371void ElfInterface::GetMaxSizeWithTemplate(Memory* memory, uint64_t* size) {
372 EhdrType ehdr;
373 if (!memory->Read(0, &ehdr, sizeof(ehdr))) {
374 return;
375 }
376 if (ehdr.e_shnum == 0) {
377 return;
378 }
379 *size = ehdr.e_shoff + ehdr.e_shentsize * ehdr.e_shnum;
380}
381
Christopher Ferris3958f802017-02-01 15:44:40 -0800382// Instantiate all of the needed template functions.
Christopher Ferris61d40972017-06-12 19:14:20 -0700383template void ElfInterface::InitHeadersWithTemplate<uint32_t>();
384template void ElfInterface::InitHeadersWithTemplate<uint64_t>();
385
Christopher Ferrise69f4702017-10-19 16:08:58 -0700386template bool ElfInterface::ReadAllHeaders<Elf32_Ehdr, Elf32_Phdr, Elf32_Shdr>(uint64_t*);
387template bool ElfInterface::ReadAllHeaders<Elf64_Ehdr, Elf64_Phdr, Elf64_Shdr>(uint64_t*);
Christopher Ferris3958f802017-02-01 15:44:40 -0800388
Christopher Ferrise69f4702017-10-19 16:08:58 -0700389template bool ElfInterface::ReadProgramHeaders<Elf32_Ehdr, Elf32_Phdr>(const Elf32_Ehdr&, uint64_t*);
390template bool ElfInterface::ReadProgramHeaders<Elf64_Ehdr, Elf64_Phdr>(const Elf64_Ehdr&, uint64_t*);
Christopher Ferris3958f802017-02-01 15:44:40 -0800391
392template bool ElfInterface::ReadSectionHeaders<Elf32_Ehdr, Elf32_Shdr>(const Elf32_Ehdr&);
393template bool ElfInterface::ReadSectionHeaders<Elf64_Ehdr, Elf64_Shdr>(const Elf64_Ehdr&);
394
395template bool ElfInterface::GetSonameWithTemplate<Elf32_Dyn>(std::string*);
396template bool ElfInterface::GetSonameWithTemplate<Elf64_Dyn>(std::string*);
Christopher Ferris8098b1c2017-06-20 13:54:08 -0700397
Christopher Ferrise69f4702017-10-19 16:08:58 -0700398template bool ElfInterface::GetFunctionNameWithTemplate<Elf32_Sym>(uint64_t, uint64_t, std::string*,
Christopher Ferris8098b1c2017-06-20 13:54:08 -0700399 uint64_t*);
Christopher Ferrise69f4702017-10-19 16:08:58 -0700400template bool ElfInterface::GetFunctionNameWithTemplate<Elf64_Sym>(uint64_t, uint64_t, std::string*,
Christopher Ferris8098b1c2017-06-20 13:54:08 -0700401 uint64_t*);
Christopher Ferrisd226a512017-07-14 10:37:19 -0700402
Christopher Ferris3f805ac2017-08-30 13:15:19 -0700403template void ElfInterface::GetMaxSizeWithTemplate<Elf32_Ehdr>(Memory*, uint64_t*);
404template void ElfInterface::GetMaxSizeWithTemplate<Elf64_Ehdr>(Memory*, uint64_t*);
405
Christopher Ferrisd226a512017-07-14 10:37:19 -0700406} // namespace unwindstack