blob: 087457c0287f7c9f1a695ddb1af03bfc5ff7896a [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
23#include "ElfInterface.h"
24#include "Memory.h"
25#include "Regs.h"
26
27template <typename EhdrType, typename PhdrType, typename ShdrType>
28bool 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
40template <typename EhdrType, typename PhdrType>
41bool 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;
Christopher Ferrisf447c8e2017-04-03 12:39:47 -070045 if (!memory_->ReadField(offset, &phdr, &phdr.p_type, sizeof(phdr.p_type))) {
Christopher Ferris3958f802017-02-01 15:44:40 -080046 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.
Christopher Ferrisf447c8e2017-04-03 12:39:47 -070057 if (!memory_->ReadField(offset, &phdr, &phdr.p_flags, sizeof(phdr.p_flags))) {
Christopher Ferris3958f802017-02-01 15:44:40 -080058 return false;
59 }
60 if ((phdr.p_flags & PF_X) == 0) {
61 continue;
62 }
63
Christopher Ferrisf447c8e2017-04-03 12:39:47 -070064 if (!memory_->ReadField(offset, &phdr, &phdr.p_vaddr, sizeof(phdr.p_vaddr))) {
Christopher Ferris3958f802017-02-01 15:44:40 -080065 return false;
66 }
Christopher Ferrisf447c8e2017-04-03 12:39:47 -070067 if (!memory_->ReadField(offset, &phdr, &phdr.p_offset, sizeof(phdr.p_offset))) {
Christopher Ferris3958f802017-02-01 15:44:40 -080068 return false;
69 }
Christopher Ferrisf447c8e2017-04-03 12:39:47 -070070 if (!memory_->ReadField(offset, &phdr, &phdr.p_memsz, sizeof(phdr.p_memsz))) {
Christopher Ferris3958f802017-02-01 15:44:40 -080071 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:
Christopher Ferrisf447c8e2017-04-03 12:39:47 -070082 if (!memory_->ReadField(offset, &phdr, &phdr.p_offset, sizeof(phdr.p_offset))) {
Christopher Ferris3958f802017-02-01 15:44:40 -080083 return false;
84 }
85 eh_frame_offset_ = phdr.p_offset;
Christopher Ferrisf447c8e2017-04-03 12:39:47 -070086 if (!memory_->ReadField(offset, &phdr, &phdr.p_memsz, sizeof(phdr.p_memsz))) {
Christopher Ferris3958f802017-02-01 15:44:40 -080087 return false;
88 }
89 eh_frame_size_ = phdr.p_memsz;
90 break;
91
92 case PT_DYNAMIC:
Christopher Ferrisf447c8e2017-04-03 12:39:47 -070093 if (!memory_->ReadField(offset, &phdr, &phdr.p_offset, sizeof(phdr.p_offset))) {
Christopher Ferris3958f802017-02-01 15:44:40 -080094 return false;
95 }
96 dynamic_offset_ = phdr.p_offset;
Christopher Ferrisf447c8e2017-04-03 12:39:47 -070097 if (!memory_->ReadField(offset, &phdr, &phdr.p_memsz, sizeof(phdr.p_memsz))) {
Christopher Ferris3958f802017-02-01 15:44:40 -080098 return false;
99 }
100 dynamic_size_ = phdr.p_memsz;
101 break;
102 }
103 }
104 return true;
105}
106
107template <typename EhdrType, typename ShdrType>
108bool 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;
Christopher Ferrisf447c8e2017-04-03 12:39:47 -0700119 if (memory_->ReadField(sh_offset, &shdr, &shdr.sh_offset, sizeof(shdr.sh_offset)) &&
120 memory_->ReadField(sh_offset, &shdr, &shdr.sh_size, sizeof(shdr.sh_size))) {
Christopher Ferris3958f802017-02-01 15:44:40 -0800121 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) {
Christopher Ferrisf447c8e2017-04-03 12:39:47 -0700128 if (!memory_->ReadField(offset, &shdr, &shdr.sh_type, sizeof(shdr.sh_type))) {
Christopher Ferris3958f802017-02-01 15:44:40 -0800129 return false;
130 }
131
132 if (shdr.sh_type == SHT_PROGBITS) {
133 // Look for the .debug_frame and .gnu_debugdata.
Christopher Ferrisf447c8e2017-04-03 12:39:47 -0700134 if (!memory_->ReadField(offset, &shdr, &shdr.sh_name, sizeof(shdr.sh_name))) {
Christopher Ferris3958f802017-02-01 15:44:40 -0800135 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") {
Christopher Ferrisf447c8e2017-04-03 12:39:47 -0700141 if (memory_->ReadField(offset, &shdr, &shdr.sh_offset, sizeof(shdr.sh_offset)) &&
142 memory_->ReadField(offset, &shdr, &shdr.sh_size, sizeof(shdr.sh_size))) {
Christopher Ferris3958f802017-02-01 15:44:40 -0800143 debug_frame_offset_ = shdr.sh_offset;
144 debug_frame_size_ = shdr.sh_size;
145 }
146 } else if (name == ".gnu_debugdata") {
Christopher Ferrisf447c8e2017-04-03 12:39:47 -0700147 if (memory_->ReadField(offset, &shdr, &shdr.sh_offset, sizeof(shdr.sh_offset)) &&
148 memory_->ReadField(offset, &shdr, &shdr.sh_size, sizeof(shdr.sh_size))) {
Christopher Ferris3958f802017-02-01 15:44:40 -0800149 gnu_debugdata_offset_ = shdr.sh_offset;
150 gnu_debugdata_size_ = shdr.sh_size;
151 }
152 }
153 }
154 }
155 }
156 }
157 return true;
158}
159
160template <typename DynType>
161bool 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
208bool ElfInterface::Step(uint64_t, Regs*, Memory*) {
209 return false;
210}
211
212// Instantiate all of the needed template functions.
213template bool ElfInterface::ReadAllHeaders<Elf32_Ehdr, Elf32_Phdr, Elf32_Shdr>();
214template bool ElfInterface::ReadAllHeaders<Elf64_Ehdr, Elf64_Phdr, Elf64_Shdr>();
215
216template bool ElfInterface::ReadProgramHeaders<Elf32_Ehdr, Elf32_Phdr>(const Elf32_Ehdr&);
217template bool ElfInterface::ReadProgramHeaders<Elf64_Ehdr, Elf64_Phdr>(const Elf64_Ehdr&);
218
219template bool ElfInterface::ReadSectionHeaders<Elf32_Ehdr, Elf32_Shdr>(const Elf32_Ehdr&);
220template bool ElfInterface::ReadSectionHeaders<Elf64_Ehdr, Elf64_Shdr>(const Elf64_Ehdr&);
221
222template bool ElfInterface::GetSonameWithTemplate<Elf32_Dyn>(std::string*);
223template bool ElfInterface::GetSonameWithTemplate<Elf64_Dyn>(std::string*);