• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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