1 /*
2 * Copyright (C) 2012 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_file.h"
18
19 #include <inttypes.h>
20 #include <sys/mman.h> // For the PROT_* and MAP_* constants.
21 #include <sys/types.h>
22 #include <unistd.h>
23
24 #include <cstddef>
25 #include <memory>
26
27 #include "android-base/stringprintf.h"
28 #include "arch/instruction_set.h"
29 #include "base/casts.h"
30 #include "base/os.h"
31 #include "base/unix_file/fd_file.h"
32 #include "elf/elf_utils.h"
33 #include "elf_file_impl.h"
34
35 namespace art HIDDEN {
36
37 using android::base::StringPrintf;
38
39 template <typename ElfTypes>
Open(File * file,off_t start,size_t file_length,const std::string & file_location,bool low_4gb,std::string * error_msg)40 ElfFileImpl<ElfTypes>* ElfFileImpl<ElfTypes>::Open(File* file,
41 off_t start,
42 size_t file_length,
43 const std::string& file_location,
44 bool low_4gb,
45 std::string* error_msg) {
46 std::unique_ptr<ElfFileImpl<ElfTypes>> elf_file(
47 new ElfFileImpl<ElfTypes>(file, start, file_length, file_location));
48 if (!elf_file->Setup(low_4gb, error_msg)) {
49 return nullptr;
50 }
51 return elf_file.release();
52 }
53
54 template <typename ElfTypes>
Setup(bool low_4gb,std::string * error_msg)55 bool ElfFileImpl<ElfTypes>::Setup(bool low_4gb, std::string* error_msg) {
56 if (file_length_ < sizeof(Elf_Ehdr)) {
57 *error_msg = StringPrintf(
58 "File size of %zd bytes not large enough to contain ELF header of "
59 "%zd bytes: '%s'",
60 file_length_,
61 sizeof(Elf_Ehdr),
62 file_location_.c_str());
63 return false;
64 }
65
66 int prot = PROT_READ;
67 int flags = MAP_PRIVATE;
68
69 // first just map ELF header to get program header size information
70 size_t elf_header_size = sizeof(Elf_Ehdr);
71 if (!SetMap(MemMap::MapFile(elf_header_size,
72 prot,
73 flags,
74 file_->Fd(),
75 start_,
76 low_4gb,
77 file_location_.c_str(),
78 error_msg),
79 error_msg)) {
80 return false;
81 }
82 // then remap to cover program header
83 size_t program_header_size = header_->e_phoff + (header_->e_phentsize * header_->e_phnum);
84 if (file_length_ < program_header_size) {
85 *error_msg = StringPrintf(
86 "File size of %zd bytes not large enough to contain ELF program header of %zd bytes: '%s'",
87 file_length_,
88 sizeof(Elf_Ehdr),
89 file_location_.c_str());
90 return false;
91 }
92 if (!SetMap(MemMap::MapFile(program_header_size,
93 prot,
94 flags,
95 file_->Fd(),
96 start_,
97 low_4gb,
98 file_location_.c_str(),
99 error_msg),
100 error_msg)) {
101 *error_msg = StringPrintf("Failed to map ELF program headers: %s", error_msg->c_str());
102 return false;
103 }
104
105 program_headers_start_ = Begin() + GetHeader().e_phoff;
106
107 return true;
108 }
109
110 template <typename ElfTypes>
CheckSectionsExist(std::string * error_msg) const111 bool ElfFileImpl<ElfTypes>::CheckSectionsExist(std::string* error_msg) const {
112 // This is redundant, but defensive.
113 if (dynamic_program_header_ == nullptr) {
114 *error_msg = StringPrintf("Failed to find PT_DYNAMIC program header in ELF file: '%s'",
115 file_location_.c_str());
116 return false;
117 }
118
119 // Need a dynamic section. This is redundant, but defensive.
120 if (dynamic_section_start_ == nullptr) {
121 *error_msg =
122 StringPrintf("Failed to find dynamic section in ELF file: '%s'", file_location_.c_str());
123 return false;
124 }
125
126 // Symtab validation. These is not really a hard failure, as we are currently not using the
127 // symtab internally, but it's nice to be defensive.
128 if (symtab_section_start_ != nullptr) {
129 // When there's a symtab, there should be a strtab.
130 if (strtab_section_start_ == nullptr) {
131 *error_msg = StringPrintf("No strtab for symtab in ELF file: '%s'", file_location_.c_str());
132 return false;
133 }
134 }
135
136 // We always need a dynstr & dynsym.
137 if (dynstr_section_start_ == nullptr) {
138 *error_msg = StringPrintf("No dynstr in ELF file: '%s'", file_location_.c_str());
139 return false;
140 }
141 if (dynsym_section_start_ == nullptr) {
142 *error_msg = StringPrintf("No dynsym in ELF file: '%s'", file_location_.c_str());
143 return false;
144 }
145
146 // Need a hash section for dynamic symbol lookup.
147 if (hash_section_start_ == nullptr) {
148 *error_msg =
149 StringPrintf("Failed to find hash section in ELF file: '%s'", file_location_.c_str());
150 return false;
151 }
152
153 // We'd also like to confirm a shstrtab. This is usually the last in an oat file, and a good
154 // indicator of whether writing was successful (or the process crashed and left garbage).
155 // It might not be mapped, but we can compare against the file size.
156 size_t offset = GetHeader().e_shoff + (GetHeader().e_shstrndx * GetHeader().e_shentsize);
157 if (offset >= file_length_) {
158 *error_msg =
159 StringPrintf("Shstrtab is not in the mapped ELF file: '%s'", file_location_.c_str());
160 return false;
161 }
162
163 return true;
164 }
165
166 template <typename ElfTypes>
SetMap(MemMap && map,std::string * error_msg)167 bool ElfFileImpl<ElfTypes>::SetMap(MemMap&& map, std::string* error_msg) {
168 if (!map.IsValid()) {
169 // MemMap::Open should have already set an error.
170 DCHECK(!error_msg->empty());
171 return false;
172 }
173 map_ = std::move(map);
174 CHECK(map_.IsValid()) << file_location_;
175 CHECK(map_.Begin() != nullptr) << file_location_;
176
177 header_ = reinterpret_cast<Elf_Ehdr*>(map_.Begin());
178 if ((ELFMAG0 != header_->e_ident[EI_MAG0])
179 || (ELFMAG1 != header_->e_ident[EI_MAG1])
180 || (ELFMAG2 != header_->e_ident[EI_MAG2])
181 || (ELFMAG3 != header_->e_ident[EI_MAG3])) {
182 *error_msg = StringPrintf("Failed to find ELF magic value %d %d %d %d in %s, found %d %d %d %d",
183 ELFMAG0,
184 ELFMAG1,
185 ELFMAG2,
186 ELFMAG3,
187 file_location_.c_str(),
188 header_->e_ident[EI_MAG0],
189 header_->e_ident[EI_MAG1],
190 header_->e_ident[EI_MAG2],
191 header_->e_ident[EI_MAG3]);
192 return false;
193 }
194 uint8_t elf_class = (sizeof(Elf_Addr) == sizeof(Elf64_Addr)) ? ELFCLASS64 : ELFCLASS32;
195 if (elf_class != header_->e_ident[EI_CLASS]) {
196 *error_msg = StringPrintf("Failed to find expected EI_CLASS value %d in %s, found %d",
197 elf_class,
198 file_location_.c_str(),
199 header_->e_ident[EI_CLASS]);
200 return false;
201 }
202 if (ELFDATA2LSB != header_->e_ident[EI_DATA]) {
203 *error_msg = StringPrintf("Failed to find expected EI_DATA value %d in %s, found %d",
204 ELFDATA2LSB,
205 file_location_.c_str(),
206 header_->e_ident[EI_CLASS]);
207 return false;
208 }
209 if (EV_CURRENT != header_->e_ident[EI_VERSION]) {
210 *error_msg = StringPrintf("Failed to find expected EI_VERSION value %d in %s, found %d",
211 EV_CURRENT,
212 file_location_.c_str(),
213 header_->e_ident[EI_CLASS]);
214 return false;
215 }
216 if (ET_DYN != header_->e_type) {
217 *error_msg = StringPrintf("Failed to find expected e_type value %d in %s, found %d",
218 ET_DYN,
219 file_location_.c_str(),
220 header_->e_type);
221 return false;
222 }
223 if (EV_CURRENT != header_->e_version) {
224 *error_msg = StringPrintf("Failed to find expected e_version value %d in %s, found %d",
225 EV_CURRENT,
226 file_location_.c_str(),
227 header_->e_version);
228 return false;
229 }
230 if (0 != header_->e_entry) {
231 *error_msg = StringPrintf("Failed to find expected e_entry value %d in %s, found %d",
232 0,
233 file_location_.c_str(),
234 static_cast<int32_t>(header_->e_entry));
235 return false;
236 }
237 if (0 == header_->e_phoff) {
238 *error_msg =
239 StringPrintf("Failed to find non-zero e_phoff value in %s", file_location_.c_str());
240 return false;
241 }
242 if (0 == header_->e_shoff) {
243 *error_msg =
244 StringPrintf("Failed to find non-zero e_shoff value in %s", file_location_.c_str());
245 return false;
246 }
247 if (0 == header_->e_ehsize) {
248 *error_msg =
249 StringPrintf("Failed to find non-zero e_ehsize value in %s", file_location_.c_str());
250 return false;
251 }
252 if (0 == header_->e_phentsize) {
253 *error_msg =
254 StringPrintf("Failed to find non-zero e_phentsize value in %s", file_location_.c_str());
255 return false;
256 }
257 if (0 == header_->e_phnum) {
258 *error_msg =
259 StringPrintf("Failed to find non-zero e_phnum value in %s", file_location_.c_str());
260 return false;
261 }
262 if (0 == header_->e_shentsize) {
263 *error_msg =
264 StringPrintf("Failed to find non-zero e_shentsize value in %s", file_location_.c_str());
265 return false;
266 }
267 if (0 == header_->e_shnum) {
268 *error_msg =
269 StringPrintf("Failed to find non-zero e_shnum value in %s", file_location_.c_str());
270 return false;
271 }
272 if (0 == header_->e_shstrndx) {
273 *error_msg =
274 StringPrintf("Failed to find non-zero e_shstrndx value in %s", file_location_.c_str());
275 return false;
276 }
277 if (header_->e_shstrndx >= header_->e_shnum) {
278 *error_msg = StringPrintf("Failed to find e_shnum value %d less than %d in %s",
279 header_->e_shstrndx,
280 header_->e_shnum,
281 file_location_.c_str());
282 return false;
283 }
284 return true;
285 }
286
287 template <typename ElfTypes>
GetHeader() const288 typename ElfTypes::Ehdr& ElfFileImpl<ElfTypes>::GetHeader() const {
289 CHECK(header_ != nullptr); // Header has been checked in SetMap
290 return *header_;
291 }
292
293 template <typename ElfTypes>
GetProgramHeadersStart() const294 uint8_t* ElfFileImpl<ElfTypes>::GetProgramHeadersStart() const {
295 CHECK(program_headers_start_ != nullptr); // Header has been set in Setup
296 return program_headers_start_;
297 }
298
299 template <typename ElfTypes>
GetDynamicProgramHeader() const300 typename ElfTypes::Phdr& ElfFileImpl<ElfTypes>::GetDynamicProgramHeader() const {
301 CHECK(dynamic_program_header_ != nullptr); // Is checked in CheckSectionsExist
302 return *dynamic_program_header_;
303 }
304
305 template <typename ElfTypes>
GetDynamicSectionStart() const306 typename ElfTypes::Dyn* ElfFileImpl<ElfTypes>::GetDynamicSectionStart() const {
307 CHECK(dynamic_section_start_ != nullptr); // Is checked in CheckSectionsExist
308 return dynamic_section_start_;
309 }
310
311 template <typename ElfTypes>
GetSymbolSectionStart(Elf_Word section_type) const312 typename ElfTypes::Sym* ElfFileImpl<ElfTypes>::GetSymbolSectionStart(
313 Elf_Word section_type) const {
314 CHECK(IsSymbolSectionType(section_type)) << file_location_ << " " << section_type;
315 switch (section_type) {
316 case SHT_SYMTAB: {
317 return symtab_section_start_;
318 break;
319 }
320 case SHT_DYNSYM: {
321 return dynsym_section_start_;
322 break;
323 }
324 default: {
325 LOG(FATAL) << section_type;
326 return nullptr;
327 }
328 }
329 }
330
331 template <typename ElfTypes>
GetStringSectionStart(Elf_Word section_type) const332 const char* ElfFileImpl<ElfTypes>::GetStringSectionStart(
333 Elf_Word section_type) const {
334 CHECK(IsSymbolSectionType(section_type)) << file_location_ << " " << section_type;
335 switch (section_type) {
336 case SHT_SYMTAB: {
337 return strtab_section_start_;
338 }
339 case SHT_DYNSYM: {
340 return dynstr_section_start_;
341 }
342 default: {
343 LOG(FATAL) << section_type;
344 return nullptr;
345 }
346 }
347 }
348
349 template <typename ElfTypes>
GetString(Elf_Word section_type,Elf_Word i) const350 const char* ElfFileImpl<ElfTypes>::GetString(Elf_Word section_type,
351 Elf_Word i) const {
352 CHECK(IsSymbolSectionType(section_type)) << file_location_ << " " << section_type;
353 if (i == 0) {
354 return nullptr;
355 }
356 const char* string_section_start = GetStringSectionStart(section_type);
357 if (string_section_start == nullptr) {
358 return nullptr;
359 }
360 return string_section_start + i;
361 }
362
363 // WARNING: The following methods do not check for an error condition (non-existent hash section).
364 // It is the caller's job to do this.
365
366 template <typename ElfTypes>
GetHashSectionStart() const367 typename ElfTypes::Word* ElfFileImpl<ElfTypes>::GetHashSectionStart() const {
368 return hash_section_start_;
369 }
370
371 template <typename ElfTypes>
GetHashBucketNum() const372 typename ElfTypes::Word ElfFileImpl<ElfTypes>::GetHashBucketNum() const {
373 return GetHashSectionStart()[0];
374 }
375
376 template <typename ElfTypes>
GetHashChainNum() const377 typename ElfTypes::Word ElfFileImpl<ElfTypes>::GetHashChainNum() const {
378 return GetHashSectionStart()[1];
379 }
380
381 template <typename ElfTypes>
GetHashBucket(size_t i,bool * ok) const382 typename ElfTypes::Word ElfFileImpl<ElfTypes>::GetHashBucket(size_t i, bool* ok) const {
383 if (i >= GetHashBucketNum()) {
384 *ok = false;
385 return 0;
386 }
387 *ok = true;
388 // 0 is nbucket, 1 is nchain
389 return GetHashSectionStart()[2 + i];
390 }
391
392 template <typename ElfTypes>
GetHashChain(size_t i,bool * ok) const393 typename ElfTypes::Word ElfFileImpl<ElfTypes>::GetHashChain(size_t i, bool* ok) const {
394 if (i >= GetHashChainNum()) {
395 *ok = false;
396 return 0;
397 }
398 *ok = true;
399 // 0 is nbucket, 1 is nchain, & chains are after buckets
400 return GetHashSectionStart()[2 + GetHashBucketNum() + i];
401 }
402
403 template <typename ElfTypes>
GetProgramHeaderNum() const404 typename ElfTypes::Word ElfFileImpl<ElfTypes>::GetProgramHeaderNum() const {
405 return GetHeader().e_phnum;
406 }
407
408 template <typename ElfTypes>
GetProgramHeader(Elf_Word i) const409 typename ElfTypes::Phdr* ElfFileImpl<ElfTypes>::GetProgramHeader(Elf_Word i) const {
410 CHECK_LT(i, GetProgramHeaderNum()) << file_location_; // Validity check for caller.
411 uint8_t* program_header = GetProgramHeadersStart() + (i * GetHeader().e_phentsize);
412 CHECK_LT(program_header, End());
413 return reinterpret_cast<Elf_Phdr*>(program_header);
414 }
415
416 template <typename ElfTypes>
FindProgamHeaderByType(Elf_Word type) const417 typename ElfTypes::Phdr* ElfFileImpl<ElfTypes>::FindProgamHeaderByType(Elf_Word type) const {
418 for (Elf_Word i = 0; i < GetProgramHeaderNum(); i++) {
419 Elf_Phdr* program_header = GetProgramHeader(i);
420 if (program_header->p_type == type) {
421 return program_header;
422 }
423 }
424 return nullptr;
425 }
426
427 template <typename ElfTypes>
GetSectionHeaderNum() const428 typename ElfTypes::Word ElfFileImpl<ElfTypes>::GetSectionHeaderNum() const {
429 return GetHeader().e_shnum;
430 }
431
432 // from bionic
elfhash(const char * _name)433 static unsigned elfhash(const char *_name) {
434 const unsigned char *name = (const unsigned char *) _name;
435 unsigned h = 0, g;
436
437 while (*name) {
438 h = (h << 4) + *name++;
439 g = h & 0xf0000000;
440 h ^= g;
441 h ^= g >> 24;
442 }
443 return h;
444 }
445
446 template <typename ElfTypes>
FindDynamicSymbolAddress(const std::string & symbol_name) const447 const uint8_t* ElfFileImpl<ElfTypes>::FindDynamicSymbolAddress(
448 const std::string& symbol_name) const {
449 // Check that we have a hash section.
450 if (GetHashSectionStart() == nullptr) {
451 return nullptr; // Failure condition.
452 }
453 const Elf_Sym* sym = FindDynamicSymbol(symbol_name);
454 if (sym != nullptr) {
455 // TODO: we need to change this to calculate base_address_ in ::Open,
456 // otherwise it will be wrongly 0 if ::Load has not yet been called.
457 return base_address_ + sym->st_value;
458 } else {
459 return nullptr;
460 }
461 }
462
463 // WARNING: Only called from FindDynamicSymbolAddress. Elides check for hash section.
464 template <typename ElfTypes>
FindDynamicSymbol(const std::string & symbol_name) const465 const typename ElfTypes::Sym* ElfFileImpl<ElfTypes>::FindDynamicSymbol(
466 const std::string& symbol_name) const {
467 if (GetHashBucketNum() == 0) {
468 // No dynamic symbols at all.
469 return nullptr;
470 }
471 Elf_Word hash = elfhash(symbol_name.c_str());
472 Elf_Word bucket_index = hash % GetHashBucketNum();
473 bool ok;
474 Elf_Word symbol_and_chain_index = GetHashBucket(bucket_index, &ok);
475 if (!ok) {
476 return nullptr;
477 }
478 while (symbol_and_chain_index != 0 /* STN_UNDEF */) {
479 Elf_Sym* symbol = GetSymbol(SHT_DYNSYM, symbol_and_chain_index);
480 if (symbol == nullptr) {
481 return nullptr; // Failure condition.
482 }
483 const char* name = GetString(SHT_DYNSYM, symbol->st_name);
484 if (symbol_name == name) {
485 return symbol;
486 }
487 symbol_and_chain_index = GetHashChain(symbol_and_chain_index, &ok);
488 if (!ok) {
489 return nullptr;
490 }
491 }
492 return nullptr;
493 }
494
495 template <typename ElfTypes>
IsSymbolSectionType(Elf_Word section_type)496 bool ElfFileImpl<ElfTypes>::IsSymbolSectionType(Elf_Word section_type) {
497 return ((section_type == SHT_SYMTAB) || (section_type == SHT_DYNSYM));
498 }
499
500 template <typename ElfTypes>
GetSymbolNum(Elf_Shdr & section_header) const501 typename ElfTypes::Word ElfFileImpl<ElfTypes>::GetSymbolNum(Elf_Shdr& section_header) const {
502 CHECK(IsSymbolSectionType(section_header.sh_type))
503 << file_location_ << " " << section_header.sh_type;
504 CHECK_NE(0U, section_header.sh_entsize) << file_location_;
505 return section_header.sh_size / section_header.sh_entsize;
506 }
507
508 template <typename ElfTypes>
GetSymbol(Elf_Word section_type,Elf_Word i) const509 typename ElfTypes::Sym* ElfFileImpl<ElfTypes>::GetSymbol(Elf_Word section_type, Elf_Word i) const {
510 Elf_Sym* sym_start = GetSymbolSectionStart(section_type);
511 if (sym_start == nullptr) {
512 return nullptr;
513 }
514 return sym_start + i;
515 }
516
517 template <typename ElfTypes>
GetDynamicNum() const518 typename ElfTypes::Word ElfFileImpl<ElfTypes>::GetDynamicNum() const {
519 return GetDynamicProgramHeader().p_filesz / sizeof(Elf_Dyn);
520 }
521
522 template <typename ElfTypes>
GetDynamic(Elf_Word i) const523 typename ElfTypes::Dyn& ElfFileImpl<ElfTypes>::GetDynamic(Elf_Word i) const {
524 CHECK_LT(i, GetDynamicNum()) << file_location_;
525 return *(GetDynamicSectionStart() + i);
526 }
527
528 template <typename ElfTypes>
GetLoadedSize(size_t * size,std::string * error_msg) const529 bool ElfFileImpl<ElfTypes>::GetLoadedSize(size_t* size, std::string* error_msg) const {
530 uint8_t* vaddr_begin;
531 return GetLoadedAddressRange(&vaddr_begin, size, error_msg);
532 }
533
534 template <typename ElfTypes>
GetElfSegmentAlignmentFromFile() const535 size_t ElfFileImpl<ElfTypes>::GetElfSegmentAlignmentFromFile() const {
536 // Return the alignment of the first loadable program segment.
537 for (Elf_Word i = 0; i < GetProgramHeaderNum(); i++) {
538 Elf_Phdr* program_header = GetProgramHeader(i);
539 if (program_header->p_type != PT_LOAD) {
540 continue;
541 }
542 return program_header->p_align;
543 }
544 LOG(ERROR) << "No loadable segment found in ELF file " << file_location_;
545 return 0;
546 }
547
548 // Base on bionic phdr_table_get_load_size
549 template <typename ElfTypes>
GetLoadedAddressRange(uint8_t ** vaddr_begin,size_t * vaddr_size,std::string * error_msg) const550 bool ElfFileImpl<ElfTypes>::GetLoadedAddressRange(/*out*/uint8_t** vaddr_begin,
551 /*out*/size_t* vaddr_size,
552 /*out*/std::string* error_msg) const {
553 Elf_Addr min_vaddr = static_cast<Elf_Addr>(-1);
554 Elf_Addr max_vaddr = 0u;
555 for (Elf_Word i = 0; i < GetProgramHeaderNum(); i++) {
556 Elf_Phdr* program_header = GetProgramHeader(i);
557 if (program_header->p_type != PT_LOAD) {
558 continue;
559 }
560 Elf_Addr begin_vaddr = program_header->p_vaddr;
561 if (begin_vaddr < min_vaddr) {
562 min_vaddr = begin_vaddr;
563 }
564 Elf_Addr end_vaddr = program_header->p_vaddr + program_header->p_memsz;
565 if (UNLIKELY(begin_vaddr > end_vaddr)) {
566 std::ostringstream oss;
567 oss << "Program header #" << i << " has overflow in p_vaddr+p_memsz: 0x" << std::hex
568 << program_header->p_vaddr << "+0x" << program_header->p_memsz << "=0x" << end_vaddr
569 << " in ELF file \"" << file_location_ << "\"";
570 *error_msg = oss.str();
571 *vaddr_begin = nullptr;
572 *vaddr_size = static_cast<size_t>(-1);
573 return false;
574 }
575 if (end_vaddr > max_vaddr) {
576 max_vaddr = end_vaddr;
577 }
578 }
579 min_vaddr = RoundDown(min_vaddr, kElfSegmentAlignment);
580 max_vaddr = RoundUp(max_vaddr, kElfSegmentAlignment);
581 CHECK_LT(min_vaddr, max_vaddr) << file_location_;
582 // Check that the range fits into the runtime address space.
583 if (UNLIKELY(max_vaddr - 1u > std::numeric_limits<size_t>::max())) {
584 std::ostringstream oss;
585 oss << "Loaded range is 0x" << std::hex << min_vaddr << "-0x" << max_vaddr
586 << " but maximum size_t is 0x" << std::numeric_limits<size_t>::max() << " for ELF file \""
587 << file_location_ << "\"";
588 *error_msg = oss.str();
589 *vaddr_begin = nullptr;
590 *vaddr_size = static_cast<size_t>(-1);
591 return false;
592 }
593 *vaddr_begin = reinterpret_cast<uint8_t*>(min_vaddr);
594 *vaddr_size = dchecked_integral_cast<size_t>(max_vaddr - min_vaddr);
595 return true;
596 }
597
GetInstructionSetFromELF(uint16_t e_machine,uint32_t e_flags)598 static InstructionSet GetInstructionSetFromELF(uint16_t e_machine,
599 [[maybe_unused]] uint32_t e_flags) {
600 switch (e_machine) {
601 case EM_ARM:
602 return InstructionSet::kArm;
603 case EM_AARCH64:
604 return InstructionSet::kArm64;
605 case EM_RISCV:
606 return InstructionSet::kRiscv64;
607 case EM_386:
608 return InstructionSet::kX86;
609 case EM_X86_64:
610 return InstructionSet::kX86_64;
611 }
612 return InstructionSet::kNone;
613 }
614
615 template <typename ElfTypes>
Load(bool executable,bool low_4gb,MemMap * reservation,std::string * error_msg)616 bool ElfFileImpl<ElfTypes>::Load(bool executable,
617 bool low_4gb,
618 /*inout*/ MemMap* reservation,
619 /*out*/ std::string* error_msg) {
620 if (executable) {
621 InstructionSet elf_ISA = GetInstructionSetFromELF(GetHeader().e_machine, GetHeader().e_flags);
622 if (elf_ISA != kRuntimeQuickCodeISA) {
623 std::ostringstream oss;
624 oss << "Expected ISA " << kRuntimeQuickCodeISA << " but found " << elf_ISA;
625 *error_msg = oss.str();
626 return false;
627 }
628 }
629
630 bool reserved = false;
631 for (Elf_Word i = 0; i < GetProgramHeaderNum(); i++) {
632 Elf_Phdr* program_header = GetProgramHeader(i);
633
634 // Record .dynamic header information for later use
635 if (program_header->p_type == PT_DYNAMIC) {
636 dynamic_program_header_ = program_header;
637 continue;
638 }
639
640 // Not something to load, move on.
641 if (program_header->p_type != PT_LOAD) {
642 continue;
643 }
644
645 // Found something to load.
646
647 // Before load the actual segments, reserve a contiguous chunk
648 // of required size and address for all segments, but with no
649 // permissions. We'll then carve that up with the proper
650 // permissions as we load the actual segments. If p_vaddr is
651 // non-zero, the segments require the specific address specified,
652 // which either was specified in the file because we already set
653 // base_address_ after the first zero segment).
654 if (!reserved) {
655 uint8_t* vaddr_begin;
656 size_t vaddr_size;
657 if (!GetLoadedAddressRange(&vaddr_begin, &vaddr_size, error_msg)) {
658 DCHECK(!error_msg->empty());
659 return false;
660 }
661 std::string reservation_name = "ElfFile reservation for " + file_location_;
662 MemMap local_reservation =
663 MemMap::MapAnonymous(reservation_name.c_str(),
664 (reservation != nullptr) ? reservation->Begin() : nullptr,
665 vaddr_size,
666 PROT_NONE,
667 low_4gb,
668 /*reuse=*/false,
669 reservation,
670 error_msg);
671 if (!local_reservation.IsValid()) {
672 *error_msg = StringPrintf("Failed to allocate %s: %s",
673 reservation_name.c_str(),
674 error_msg->c_str());
675 return false;
676 }
677 reserved = true;
678
679 // Base address is the difference of actual mapped location and the vaddr_begin.
680 base_address_ = reinterpret_cast<uint8_t*>(
681 static_cast<uintptr_t>(local_reservation.Begin() - vaddr_begin));
682 // By adding the p_vaddr of a section/symbol to base_address_ we will always get the
683 // dynamic memory address of where that object is actually mapped
684 //
685 // TODO: base_address_ needs to be calculated in ::Open, otherwise
686 // FindDynamicSymbolAddress returns the wrong values until Load is called.
687 segments_.push_back(std::move(local_reservation));
688 }
689 // empty segment, nothing to map
690 if (program_header->p_memsz == 0) {
691 continue;
692 }
693 uint8_t* p_vaddr = base_address_ + program_header->p_vaddr;
694 int prot = 0;
695 if (executable && ((program_header->p_flags & PF_X) != 0)) {
696 prot |= PROT_EXEC;
697 }
698 if ((program_header->p_flags & PF_W) != 0) {
699 prot |= PROT_WRITE;
700 }
701 if ((program_header->p_flags & PF_R) != 0) {
702 prot |= PROT_READ;
703 }
704 if (program_header->p_filesz > program_header->p_memsz) {
705 *error_msg = StringPrintf("Invalid p_filesz > p_memsz (%" PRIu64 " > %" PRIu64 "): %s",
706 static_cast<uint64_t>(program_header->p_filesz),
707 static_cast<uint64_t>(program_header->p_memsz),
708 file_location_.c_str());
709 return false;
710 }
711 if (program_header->p_filesz < program_header->p_memsz &&
712 !IsAligned<kElfSegmentAlignment>(program_header->p_filesz)) {
713 *error_msg =
714 StringPrintf("Unsupported unaligned p_filesz < p_memsz (%" PRIu64 " < %" PRIu64 "): %s",
715 static_cast<uint64_t>(program_header->p_filesz),
716 static_cast<uint64_t>(program_header->p_memsz),
717 file_location_.c_str());
718 return false;
719 }
720 if (file_length_ < (program_header->p_offset + program_header->p_filesz)) {
721 *error_msg = StringPrintf(
722 "File size of %zd bytes not large enough to contain ELF segment "
723 "%d of %" PRIu64 " bytes: '%s'",
724 file_length_,
725 i,
726 static_cast<uint64_t>(program_header->p_offset + program_header->p_filesz),
727 file_location_.c_str());
728 return false;
729 }
730 if (program_header->p_filesz != 0u) {
731 MemMap segment = MemMap::MapFileAtAddress(p_vaddr,
732 program_header->p_filesz,
733 prot,
734 MAP_PRIVATE,
735 file_->Fd(),
736 start_ + program_header->p_offset,
737 /*low_4gb=*/false,
738 file_location_.c_str(),
739 /*reuse=*/true, // implies MAP_FIXED
740 /*reservation=*/nullptr,
741 error_msg);
742 if (!segment.IsValid()) {
743 *error_msg = StringPrintf("Failed to map ELF file segment %d from %s: %s",
744 i,
745 file_location_.c_str(),
746 error_msg->c_str());
747 return false;
748 }
749 if (segment.Begin() != p_vaddr) {
750 *error_msg = StringPrintf(
751 "Failed to map ELF file segment %d from %s at expected address %p, "
752 "instead mapped to %p",
753 i,
754 file_location_.c_str(),
755 p_vaddr,
756 segment.Begin());
757 return false;
758 }
759 segments_.push_back(std::move(segment));
760 }
761 if (program_header->p_filesz < program_header->p_memsz) {
762 std::string name = StringPrintf("Zero-initialized segment %" PRIu64 " of ELF file %s",
763 static_cast<uint64_t>(i),
764 file_location_.c_str());
765 MemMap segment = MemMap::MapAnonymous(name.c_str(),
766 p_vaddr + program_header->p_filesz,
767 program_header->p_memsz - program_header->p_filesz,
768 prot,
769 /*low_4gb=*/false,
770 /*reuse=*/true,
771 /*reservation=*/nullptr,
772 error_msg);
773 if (!segment.IsValid()) {
774 *error_msg = StringPrintf("Failed to map zero-initialized ELF file segment %d from %s: %s",
775 i,
776 file_location_.c_str(),
777 error_msg->c_str());
778 return false;
779 }
780 if (segment.Begin() != p_vaddr) {
781 *error_msg = StringPrintf(
782 "Failed to map zero-initialized ELF file segment %d from %s "
783 "at expected address %p, instead mapped to %p",
784 i,
785 file_location_.c_str(),
786 p_vaddr,
787 segment.Begin());
788 return false;
789 }
790 segments_.push_back(std::move(segment));
791 }
792 }
793
794 // Now that we are done loading, .dynamic should be in memory to find .dynstr, .dynsym, .hash
795 uint8_t* dsptr = base_address_ + GetDynamicProgramHeader().p_vaddr;
796 if ((dsptr < Begin() || dsptr >= End()) && !ValidPointer(dsptr)) {
797 *error_msg =
798 StringPrintf("dynamic section address invalid in ELF file %s", file_location_.c_str());
799 return false;
800 }
801 dynamic_section_start_ = reinterpret_cast<Elf_Dyn*>(dsptr);
802
803 for (Elf_Word i = 0; i < GetDynamicNum(); i++) {
804 Elf_Dyn& elf_dyn = GetDynamic(i);
805 uint8_t* d_ptr = base_address_ + elf_dyn.d_un.d_ptr;
806 switch (elf_dyn.d_tag) {
807 case DT_HASH: {
808 if (!ValidPointer(d_ptr)) {
809 *error_msg = StringPrintf("DT_HASH value %p does not refer to a loaded ELF segment of %s",
810 d_ptr,
811 file_location_.c_str());
812 return false;
813 }
814 hash_section_start_ = reinterpret_cast<Elf_Word*>(d_ptr);
815 break;
816 }
817 case DT_STRTAB: {
818 if (!ValidPointer(d_ptr)) {
819 *error_msg = StringPrintf("DT_HASH value %p does not refer to a loaded ELF segment of %s",
820 d_ptr,
821 file_location_.c_str());
822 return false;
823 }
824 dynstr_section_start_ = reinterpret_cast<char*>(d_ptr);
825 break;
826 }
827 case DT_SYMTAB: {
828 if (!ValidPointer(d_ptr)) {
829 *error_msg = StringPrintf("DT_HASH value %p does not refer to a loaded ELF segment of %s",
830 d_ptr,
831 file_location_.c_str());
832 return false;
833 }
834 dynsym_section_start_ = reinterpret_cast<Elf_Sym*>(d_ptr);
835 break;
836 }
837 case DT_NULL: {
838 if (GetDynamicNum() != i+1) {
839 *error_msg = StringPrintf(
840 "DT_NULL found after %d .dynamic entries, "
841 "expected %d as implied by size of PT_DYNAMIC segment in %s",
842 i + 1,
843 GetDynamicNum(),
844 file_location_.c_str());
845 return false;
846 }
847 break;
848 }
849 }
850 }
851
852 // Check for the existence of some sections.
853 if (!CheckSectionsExist(error_msg)) {
854 return false;
855 }
856
857 return true;
858 }
859
860 template <typename ElfTypes>
ValidPointer(const uint8_t * start) const861 bool ElfFileImpl<ElfTypes>::ValidPointer(const uint8_t* start) const {
862 for (const MemMap& segment : segments_) {
863 if (segment.Begin() <= start && start < segment.End()) {
864 return true;
865 }
866 }
867 return false;
868 }
869
870 // Explicit instantiations
871 template class ElfFileImpl<ElfTypes32>;
872 template class ElfFileImpl<ElfTypes64>;
873
Open(File * file,off_t start,size_t file_length,const std::string & file_location,bool low_4gb,std::string * error_msg)874 ElfFile* ElfFile::Open(File* file,
875 off_t start,
876 size_t file_length,
877 const std::string& file_location,
878 bool low_4gb,
879 /*out*/ std::string* error_msg) {
880 if (file_length < EI_NIDENT) {
881 *error_msg = StringPrintf("File %s is too short to be a valid ELF file", file_location.c_str());
882 return nullptr;
883 }
884 MemMap map = MemMap::MapFile(EI_NIDENT,
885 PROT_READ,
886 MAP_PRIVATE,
887 file->Fd(),
888 start,
889 low_4gb,
890 file_location.c_str(),
891 error_msg);
892 if (!map.IsValid() || map.Size() != EI_NIDENT) {
893 return nullptr;
894 }
895 uint8_t* header = map.Begin();
896 if (header[EI_CLASS] == ELFCLASS64) {
897 return ElfFileImpl64::Open(file, start, file_length, file_location, low_4gb, error_msg);
898 } else if (header[EI_CLASS] == ELFCLASS32) {
899 return ElfFileImpl32::Open(file, start, file_length, file_location, low_4gb, error_msg);
900 } else {
901 *error_msg = StringPrintf("Failed to find expected EI_CLASS value %d or %d in %s, found %d",
902 ELFCLASS32,
903 ELFCLASS64,
904 file_location.c_str(),
905 header[EI_CLASS]);
906 return nullptr;
907 }
908 }
909
Open(File * file,bool low_4gb,std::string * error_msg)910 ElfFile* ElfFile::Open(File* file,
911 bool low_4gb,
912 /*out*/ std::string* error_msg) {
913 int64_t file_length = file->GetLength();
914 if (file_length < 0) {
915 *error_msg =
916 ART_FORMAT("Failed to get file length of '{}': {}", file->GetPath(), strerror(errno));
917 return nullptr;
918 }
919 return Open(file, /*start=*/0, file_length, file->GetPath(), low_4gb, error_msg);
920 }
921
922 } // namespace art
923