blob: bfa79443288fb54586d55a2db9b996bc31dc9d5e [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 Ferris61d40972017-06-12 19:14:20 -070023#include "DwarfDebugFrame.h"
24#include "DwarfEhFrame.h"
Christopher Ferris3958f802017-02-01 15:44:40 -080025#include "ElfInterface.h"
26#include "Memory.h"
27#include "Regs.h"
28
Christopher Ferris61d40972017-06-12 19:14:20 -070029template <typename AddressType>
30void ElfInterface::InitHeadersWithTemplate() {
31 if (eh_frame_offset_ != 0) {
32 eh_frame_.reset(new DwarfEhFrame<AddressType>(memory_));
33 if (!eh_frame_->Init(eh_frame_offset_, eh_frame_size_)) {
34 eh_frame_.reset(nullptr);
35 eh_frame_offset_ = 0;
36 eh_frame_size_ = static_cast<uint64_t>(-1);
37 }
38 }
39
40 if (debug_frame_offset_ != 0) {
41 debug_frame_.reset(new DwarfDebugFrame<AddressType>(memory_));
42 if (!debug_frame_->Init(debug_frame_offset_, debug_frame_size_)) {
43 debug_frame_.reset(nullptr);
44 debug_frame_offset_ = 0;
45 debug_frame_size_ = static_cast<uint64_t>(-1);
46 }
47 }
48}
49
Christopher Ferris3958f802017-02-01 15:44:40 -080050template <typename EhdrType, typename PhdrType, typename ShdrType>
51bool ElfInterface::ReadAllHeaders() {
52 EhdrType ehdr;
53 if (!memory_->Read(0, &ehdr, sizeof(ehdr))) {
54 return false;
55 }
56
57 if (!ReadProgramHeaders<EhdrType, PhdrType>(ehdr)) {
58 return false;
59 }
60 return ReadSectionHeaders<EhdrType, ShdrType>(ehdr);
61}
62
63template <typename EhdrType, typename PhdrType>
64bool ElfInterface::ReadProgramHeaders(const EhdrType& ehdr) {
65 uint64_t offset = ehdr.e_phoff;
66 for (size_t i = 0; i < ehdr.e_phnum; i++, offset += ehdr.e_phentsize) {
67 PhdrType phdr;
Christopher Ferrisf447c8e2017-04-03 12:39:47 -070068 if (!memory_->ReadField(offset, &phdr, &phdr.p_type, sizeof(phdr.p_type))) {
Christopher Ferris3958f802017-02-01 15:44:40 -080069 return false;
70 }
71
72 if (HandleType(offset, phdr.p_type)) {
73 continue;
74 }
75
76 switch (phdr.p_type) {
77 case PT_LOAD:
78 {
79 // Get the flags first, if this isn't an executable header, ignore it.
Christopher Ferrisf447c8e2017-04-03 12:39:47 -070080 if (!memory_->ReadField(offset, &phdr, &phdr.p_flags, sizeof(phdr.p_flags))) {
Christopher Ferris3958f802017-02-01 15:44:40 -080081 return false;
82 }
83 if ((phdr.p_flags & PF_X) == 0) {
84 continue;
85 }
86
Christopher Ferrisf447c8e2017-04-03 12:39:47 -070087 if (!memory_->ReadField(offset, &phdr, &phdr.p_vaddr, sizeof(phdr.p_vaddr))) {
Christopher Ferris3958f802017-02-01 15:44:40 -080088 return false;
89 }
Christopher Ferrisf447c8e2017-04-03 12:39:47 -070090 if (!memory_->ReadField(offset, &phdr, &phdr.p_offset, sizeof(phdr.p_offset))) {
Christopher Ferris3958f802017-02-01 15:44:40 -080091 return false;
92 }
Christopher Ferrisf447c8e2017-04-03 12:39:47 -070093 if (!memory_->ReadField(offset, &phdr, &phdr.p_memsz, sizeof(phdr.p_memsz))) {
Christopher Ferris3958f802017-02-01 15:44:40 -080094 return false;
95 }
96 pt_loads_[phdr.p_offset] = LoadInfo{phdr.p_offset, phdr.p_vaddr,
97 static_cast<size_t>(phdr.p_memsz)};
98 if (phdr.p_offset == 0) {
99 load_bias_ = phdr.p_vaddr;
100 }
101 break;
102 }
103
104 case PT_GNU_EH_FRAME:
Christopher Ferrisf447c8e2017-04-03 12:39:47 -0700105 if (!memory_->ReadField(offset, &phdr, &phdr.p_offset, sizeof(phdr.p_offset))) {
Christopher Ferris3958f802017-02-01 15:44:40 -0800106 return false;
107 }
108 eh_frame_offset_ = phdr.p_offset;
Christopher Ferrisf447c8e2017-04-03 12:39:47 -0700109 if (!memory_->ReadField(offset, &phdr, &phdr.p_memsz, sizeof(phdr.p_memsz))) {
Christopher Ferris3958f802017-02-01 15:44:40 -0800110 return false;
111 }
112 eh_frame_size_ = phdr.p_memsz;
113 break;
114
115 case PT_DYNAMIC:
Christopher Ferrisf447c8e2017-04-03 12:39:47 -0700116 if (!memory_->ReadField(offset, &phdr, &phdr.p_offset, sizeof(phdr.p_offset))) {
Christopher Ferris3958f802017-02-01 15:44:40 -0800117 return false;
118 }
119 dynamic_offset_ = phdr.p_offset;
Christopher Ferrisf447c8e2017-04-03 12:39:47 -0700120 if (!memory_->ReadField(offset, &phdr, &phdr.p_memsz, sizeof(phdr.p_memsz))) {
Christopher Ferris3958f802017-02-01 15:44:40 -0800121 return false;
122 }
123 dynamic_size_ = phdr.p_memsz;
124 break;
125 }
126 }
127 return true;
128}
129
130template <typename EhdrType, typename ShdrType>
131bool ElfInterface::ReadSectionHeaders(const EhdrType& ehdr) {
132 uint64_t offset = ehdr.e_shoff;
133 uint64_t sec_offset = 0;
134 uint64_t sec_size = 0;
135
136 // Get the location of the section header names.
137 // If something is malformed in the header table data, we aren't going
138 // to terminate, we'll simply ignore this part.
139 ShdrType shdr;
140 if (ehdr.e_shstrndx < ehdr.e_shnum) {
141 uint64_t sh_offset = offset + ehdr.e_shstrndx * ehdr.e_shentsize;
Christopher Ferrisf447c8e2017-04-03 12:39:47 -0700142 if (memory_->ReadField(sh_offset, &shdr, &shdr.sh_offset, sizeof(shdr.sh_offset)) &&
143 memory_->ReadField(sh_offset, &shdr, &shdr.sh_size, sizeof(shdr.sh_size))) {
Christopher Ferris3958f802017-02-01 15:44:40 -0800144 sec_offset = shdr.sh_offset;
145 sec_size = shdr.sh_size;
146 }
147 }
148
149 // Skip the first header, it's always going to be NULL.
150 for (size_t i = 1; i < ehdr.e_shnum; i++, offset += ehdr.e_shentsize) {
Christopher Ferrisf447c8e2017-04-03 12:39:47 -0700151 if (!memory_->ReadField(offset, &shdr, &shdr.sh_type, sizeof(shdr.sh_type))) {
Christopher Ferris3958f802017-02-01 15:44:40 -0800152 return false;
153 }
154
155 if (shdr.sh_type == SHT_PROGBITS) {
156 // Look for the .debug_frame and .gnu_debugdata.
Christopher Ferrisf447c8e2017-04-03 12:39:47 -0700157 if (!memory_->ReadField(offset, &shdr, &shdr.sh_name, sizeof(shdr.sh_name))) {
Christopher Ferris3958f802017-02-01 15:44:40 -0800158 return false;
159 }
160 if (shdr.sh_name < sec_size) {
161 std::string name;
162 if (memory_->ReadString(sec_offset + shdr.sh_name, &name)) {
163 if (name == ".debug_frame") {
Christopher Ferrisf447c8e2017-04-03 12:39:47 -0700164 if (memory_->ReadField(offset, &shdr, &shdr.sh_offset, sizeof(shdr.sh_offset)) &&
165 memory_->ReadField(offset, &shdr, &shdr.sh_size, sizeof(shdr.sh_size))) {
Christopher Ferris3958f802017-02-01 15:44:40 -0800166 debug_frame_offset_ = shdr.sh_offset;
167 debug_frame_size_ = shdr.sh_size;
168 }
169 } else if (name == ".gnu_debugdata") {
Christopher Ferrisf447c8e2017-04-03 12:39:47 -0700170 if (memory_->ReadField(offset, &shdr, &shdr.sh_offset, sizeof(shdr.sh_offset)) &&
171 memory_->ReadField(offset, &shdr, &shdr.sh_size, sizeof(shdr.sh_size))) {
Christopher Ferris3958f802017-02-01 15:44:40 -0800172 gnu_debugdata_offset_ = shdr.sh_offset;
173 gnu_debugdata_size_ = shdr.sh_size;
174 }
175 }
176 }
177 }
178 }
179 }
180 return true;
181}
182
183template <typename DynType>
184bool ElfInterface::GetSonameWithTemplate(std::string* soname) {
185 if (soname_type_ == SONAME_INVALID) {
186 return false;
187 }
188 if (soname_type_ == SONAME_VALID) {
189 *soname = soname_;
190 return true;
191 }
192
193 soname_type_ = SONAME_INVALID;
194
195 uint64_t soname_offset = 0;
196 uint64_t strtab_offset = 0;
197 uint64_t strtab_size = 0;
198
199 // Find the soname location from the dynamic headers section.
200 DynType dyn;
201 uint64_t offset = dynamic_offset_;
202 uint64_t max_offset = offset + dynamic_size_;
203 for (uint64_t offset = dynamic_offset_; offset < max_offset; offset += sizeof(DynType)) {
204 if (!memory_->Read(offset, &dyn, sizeof(dyn))) {
205 return false;
206 }
207
208 if (dyn.d_tag == DT_STRTAB) {
209 strtab_offset = dyn.d_un.d_ptr;
210 } else if (dyn.d_tag == DT_STRSZ) {
211 strtab_size = dyn.d_un.d_val;
212 } else if (dyn.d_tag == DT_SONAME) {
213 soname_offset = dyn.d_un.d_val;
214 } else if (dyn.d_tag == DT_NULL) {
215 break;
216 }
217 }
218
219 soname_offset += strtab_offset;
220 if (soname_offset >= strtab_offset + strtab_size) {
221 return false;
222 }
223 if (!memory_->ReadString(soname_offset, &soname_)) {
224 return false;
225 }
226 soname_type_ = SONAME_VALID;
227 *soname = soname_;
228 return true;
229}
230
231bool ElfInterface::Step(uint64_t, Regs*, Memory*) {
232 return false;
233}
234
235// Instantiate all of the needed template functions.
Christopher Ferris61d40972017-06-12 19:14:20 -0700236template void ElfInterface::InitHeadersWithTemplate<uint32_t>();
237template void ElfInterface::InitHeadersWithTemplate<uint64_t>();
238
Christopher Ferris3958f802017-02-01 15:44:40 -0800239template bool ElfInterface::ReadAllHeaders<Elf32_Ehdr, Elf32_Phdr, Elf32_Shdr>();
240template bool ElfInterface::ReadAllHeaders<Elf64_Ehdr, Elf64_Phdr, Elf64_Shdr>();
241
242template bool ElfInterface::ReadProgramHeaders<Elf32_Ehdr, Elf32_Phdr>(const Elf32_Ehdr&);
243template bool ElfInterface::ReadProgramHeaders<Elf64_Ehdr, Elf64_Phdr>(const Elf64_Ehdr&);
244
245template bool ElfInterface::ReadSectionHeaders<Elf32_Ehdr, Elf32_Shdr>(const Elf32_Ehdr&);
246template bool ElfInterface::ReadSectionHeaders<Elf64_Ehdr, Elf64_Shdr>(const Elf64_Ehdr&);
247
248template bool ElfInterface::GetSonameWithTemplate<Elf32_Dyn>(std::string*);
249template bool ElfInterface::GetSonameWithTemplate<Elf64_Dyn>(std::string*);