• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2015 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 "read_elf.h"
18 #include "read_apk.h"
19 
20 #include <stdio.h>
21 #include <string.h>
22 #include <sys/stat.h>
23 #include <sys/types.h>
24 
25 #include <algorithm>
26 #include <limits>
27 
28 #include <android-base/file.h>
29 #include <android-base/logging.h>
30 
31 #pragma clang diagnostic push
32 #pragma clang diagnostic ignored "-Wunused-parameter"
33 
34 #include <llvm/ADT/StringRef.h>
35 #include <llvm/Object/Binary.h>
36 #include <llvm/Object/ELFObjectFile.h>
37 #include <llvm/Object/ObjectFile.h>
38 
39 #pragma clang diagnostic pop
40 
41 #include "utils.h"
42 
43 #define ELF_NOTE_GNU "GNU"
44 #define NT_GNU_BUILD_ID 3
45 
46 using namespace simpleperf;
47 
operator <<(std::ostream & os,const ElfStatus & status)48 std::ostream& operator<<(std::ostream& os, const ElfStatus& status) {
49   switch (status) {
50     case ElfStatus::NO_ERROR:
51       os << "No error";
52       break;
53     case ElfStatus::FILE_NOT_FOUND:
54       os << "File not found";
55       break;
56     case ElfStatus::READ_FAILED:
57       os << "Read failed";
58       break;
59     case ElfStatus::FILE_MALFORMED:
60       os << "Malformed file";
61       break;
62     case ElfStatus::NO_SYMBOL_TABLE:
63       os << "No symbol table";
64       break;
65     case ElfStatus::NO_BUILD_ID:
66       os << "No build id";
67       break;
68     case ElfStatus::BUILD_ID_MISMATCH:
69       os << "Build id mismatch";
70       break;
71     case ElfStatus::SECTION_NOT_FOUND:
72       os << "Section not found";
73       break;
74   }
75   return os;
76 }
77 
IsValidElfFileMagic(const char * buf,size_t buf_size)78 bool IsValidElfFileMagic(const char* buf, size_t buf_size) {
79   static const char elf_magic[] = {0x7f, 'E', 'L', 'F'};
80   return (buf_size >= 4u && memcmp(buf, elf_magic, 4) == 0);
81 }
82 
IsValidElfFile(int fd,uint64_t file_offset)83 ElfStatus IsValidElfFile(int fd, uint64_t file_offset) {
84   char buf[4];
85   if (!android::base::ReadFullyAtOffset(fd, buf, 4, file_offset)) {
86     return ElfStatus::READ_FAILED;
87   }
88   return IsValidElfFileMagic(buf, 4) ? ElfStatus::NO_ERROR : ElfStatus::FILE_MALFORMED;
89 }
90 
GetBuildIdFromNoteSection(const char * section,size_t section_size,BuildId * build_id)91 bool GetBuildIdFromNoteSection(const char* section, size_t section_size, BuildId* build_id) {
92   const char* p = section;
93   const char* end = p + section_size;
94   while (p < end) {
95     if (p + 12 >= end) {
96       return false;
97     }
98     uint32_t namesz;
99     uint32_t descsz;
100     uint32_t type;
101     MoveFromBinaryFormat(namesz, p);
102     MoveFromBinaryFormat(descsz, p);
103     MoveFromBinaryFormat(type, p);
104     namesz = Align(namesz, 4);
105     descsz = Align(descsz, 4);
106     if ((type == NT_GNU_BUILD_ID) && (p < end) && (strcmp(p, ELF_NOTE_GNU) == 0)) {
107       const char* desc_start = p + namesz;
108       const char* desc_end = desc_start + descsz;
109       if (desc_start > p && desc_start < desc_end && desc_end <= end) {
110         *build_id = BuildId(p + namesz, descsz);
111         return true;
112       } else {
113         return false;
114       }
115     }
116     p += namesz + descsz;
117   }
118   return false;
119 }
120 
GetBuildIdFromNoteFile(const std::string & filename,BuildId * build_id)121 ElfStatus GetBuildIdFromNoteFile(const std::string& filename, BuildId* build_id) {
122   std::string content;
123   if (!android::base::ReadFileToString(filename, &content)) {
124     return ElfStatus::READ_FAILED;
125   }
126   if (!GetBuildIdFromNoteSection(content.c_str(), content.size(), build_id)) {
127     return ElfStatus::NO_BUILD_ID;
128   }
129   return ElfStatus::NO_ERROR;
130 }
131 
132 template <class ELFT>
GetBuildIdFromELFFile(const llvm::object::ELFObjectFile<ELFT> * elf,BuildId * build_id)133 ElfStatus GetBuildIdFromELFFile(const llvm::object::ELFObjectFile<ELFT>* elf, BuildId* build_id) {
134   llvm::StringRef data = elf->getData();
135   const char* binary_start = data.data();
136   const char* binary_end = data.data() + data.size();
137   for (auto it = elf->section_begin(); it != elf->section_end(); ++it) {
138     const llvm::object::ELFSectionRef& section_ref = *it;
139     if (section_ref.getType() == llvm::ELF::SHT_NOTE) {
140       if (it->getContents(data)) {
141         return ElfStatus::READ_FAILED;
142       }
143       if (data.data() < binary_start || data.data() + data.size() > binary_end) {
144         return ElfStatus::NO_BUILD_ID;
145       }
146       if (GetBuildIdFromNoteSection(data.data(), data.size(), build_id)) {
147         return ElfStatus::NO_ERROR;
148       }
149     }
150   }
151   return ElfStatus::NO_BUILD_ID;
152 }
153 
GetBuildIdFromObjectFile(llvm::object::ObjectFile * obj,BuildId * build_id)154 static ElfStatus GetBuildIdFromObjectFile(llvm::object::ObjectFile* obj, BuildId* build_id) {
155   if (auto elf = llvm::dyn_cast<llvm::object::ELF32LEObjectFile>(obj)) {
156     return GetBuildIdFromELFFile(elf, build_id);
157   } else if (auto elf = llvm::dyn_cast<llvm::object::ELF64LEObjectFile>(obj)) {
158     return GetBuildIdFromELFFile(elf, build_id);
159   }
160   return ElfStatus::FILE_MALFORMED;
161 }
162 
163 struct BinaryWrapper {
164   std::unique_ptr<llvm::MemoryBuffer> buffer;
165   std::unique_ptr<llvm::object::Binary> binary;
166   llvm::object::ObjectFile* obj = nullptr;
167 };
168 
OpenObjectFile(const std::string & filename,uint64_t file_offset,uint64_t file_size,BinaryWrapper * wrapper)169 static ElfStatus OpenObjectFile(const std::string& filename, uint64_t file_offset,
170                                 uint64_t file_size, BinaryWrapper* wrapper) {
171   if (!IsRegularFile(filename)) {
172     return ElfStatus::FILE_NOT_FOUND;
173   }
174   android::base::unique_fd fd = FileHelper::OpenReadOnly(filename);
175   if (fd == -1) {
176     return ElfStatus::READ_FAILED;
177   }
178   if (file_size == 0) {
179     file_size = GetFileSize(filename);
180     if (file_size == 0) {
181       return ElfStatus::READ_FAILED;
182     }
183   }
184   ElfStatus status = IsValidElfFile(fd, file_offset);
185   if (status != ElfStatus::NO_ERROR) {
186     return status;
187   }
188   auto buffer_or_err = llvm::MemoryBuffer::getOpenFileSlice(fd, filename, file_size, file_offset);
189   if (!buffer_or_err) {
190     return ElfStatus::READ_FAILED;
191   }
192   auto binary_or_err = llvm::object::createBinary(buffer_or_err.get()->getMemBufferRef());
193   if (!binary_or_err) {
194     return ElfStatus::READ_FAILED;
195   }
196   wrapper->buffer = std::move(buffer_or_err.get());
197   wrapper->binary = std::move(binary_or_err.get());
198   wrapper->obj = llvm::dyn_cast<llvm::object::ObjectFile>(wrapper->binary.get());
199   if (wrapper->obj == nullptr) {
200     return ElfStatus::FILE_MALFORMED;
201   }
202   return ElfStatus::NO_ERROR;
203 }
204 
OpenObjectFileInMemory(const char * data,size_t size,BinaryWrapper * wrapper)205 static ElfStatus OpenObjectFileInMemory(const char* data, size_t size, BinaryWrapper* wrapper) {
206   auto buffer = llvm::MemoryBuffer::getMemBuffer(llvm::StringRef(data, size));
207   auto binary_or_err = llvm::object::createBinary(buffer->getMemBufferRef());
208   if (!binary_or_err) {
209     return ElfStatus::FILE_MALFORMED;
210   }
211   wrapper->buffer = std::move(buffer);
212   wrapper->binary = std::move(binary_or_err.get());
213   wrapper->obj = llvm::dyn_cast<llvm::object::ObjectFile>(wrapper->binary.get());
214   if (wrapper->obj == nullptr) {
215     return ElfStatus::FILE_MALFORMED;
216   }
217   return ElfStatus::NO_ERROR;
218 }
219 
GetBuildIdFromElfFile(const std::string & filename,BuildId * build_id)220 ElfStatus GetBuildIdFromElfFile(const std::string& filename, BuildId* build_id) {
221   return GetBuildIdFromEmbeddedElfFile(filename, 0, 0, build_id);
222 }
223 
GetBuildIdFromEmbeddedElfFile(const std::string & filename,uint64_t file_offset,uint32_t file_size,BuildId * build_id)224 ElfStatus GetBuildIdFromEmbeddedElfFile(const std::string& filename, uint64_t file_offset,
225                                         uint32_t file_size, BuildId* build_id) {
226   BinaryWrapper wrapper;
227   ElfStatus result = OpenObjectFile(filename, file_offset, file_size, &wrapper);
228   if (result != ElfStatus::NO_ERROR) {
229     return result;
230   }
231   return GetBuildIdFromObjectFile(wrapper.obj, build_id);
232 }
233 
234 template <class ELFT>
ReadSectionFromELFFile(const llvm::object::ELFObjectFile<ELFT> * elf,const std::string & section_name,std::string * content)235 ElfStatus ReadSectionFromELFFile(const llvm::object::ELFObjectFile<ELFT>* elf, const std::string& section_name,
236                                  std::string* content) {
237   for (llvm::object::section_iterator it = elf->section_begin(); it != elf->section_end(); ++it) {
238     llvm::StringRef name;
239     if (it->getName(name) || name != section_name) {
240       continue;
241     }
242     llvm::StringRef data;
243     std::error_code err = it->getContents(data);
244     if (err) {
245       return ElfStatus::READ_FAILED;
246     }
247     *content = data;
248     return ElfStatus::NO_ERROR;
249   }
250   return ElfStatus::SECTION_NOT_FOUND;
251 }
252 
IsArmMappingSymbol(const char * name)253 bool IsArmMappingSymbol(const char* name) {
254   // Mapping symbols in arm, which are described in "ELF for ARM Architecture" and
255   // "ELF for ARM 64-bit Architecture". The regular expression to match mapping symbol
256   // is ^\$(a|d|t|x)(\..*)?$
257   return name[0] == '$' && strchr("adtx", name[1]) != nullptr && (name[2] == '\0' || name[2] == '.');
258 }
259 
ReadSymbolTable(llvm::object::symbol_iterator sym_begin,llvm::object::symbol_iterator sym_end,const std::function<void (const ElfFileSymbol &)> & callback,bool is_arm,const llvm::object::section_iterator & section_end)260 void ReadSymbolTable(llvm::object::symbol_iterator sym_begin,
261                      llvm::object::symbol_iterator sym_end,
262                      const std::function<void(const ElfFileSymbol&)>& callback,
263                      bool is_arm,
264                      const llvm::object::section_iterator& section_end) {
265   for (; sym_begin != sym_end; ++sym_begin) {
266     ElfFileSymbol symbol;
267     auto symbol_ref = static_cast<const llvm::object::ELFSymbolRef*>(&*sym_begin);
268     // Exclude undefined symbols, otherwise we may wrongly use them as labels in functions.
269     if (symbol_ref->getFlags() & symbol_ref->SF_Undefined) {
270       continue;
271     }
272     llvm::Expected<llvm::object::section_iterator> section_it_or_err = symbol_ref->getSection();
273     if (!section_it_or_err) {
274       continue;
275     }
276     // Symbols in .dynsym section don't have associated section.
277     if (section_it_or_err.get() != section_end) {
278       llvm::StringRef section_name;
279       if (section_it_or_err.get()->getName(section_name) || section_name.empty()) {
280         continue;
281       }
282       if (section_name == ".text") {
283         symbol.is_in_text_section = true;
284       }
285     }
286 
287     llvm::Expected<llvm::StringRef> symbol_name_or_err = symbol_ref->getName();
288     if (!symbol_name_or_err || symbol_name_or_err.get().empty()) {
289       continue;
290     }
291 
292     symbol.name = symbol_name_or_err.get();
293     symbol.vaddr = symbol_ref->getValue();
294     if ((symbol.vaddr & 1) != 0 && is_arm) {
295       // Arm sets bit 0 to mark it as thumb code, remove the flag.
296       symbol.vaddr &= ~1;
297     }
298     symbol.len = symbol_ref->getSize();
299     llvm::object::SymbolRef::Type symbol_type = *symbol_ref->getType();
300     if (symbol_type == llvm::object::SymbolRef::ST_Function) {
301       symbol.is_func = true;
302     } else if (symbol_type == llvm::object::SymbolRef::ST_Unknown) {
303       if (symbol.is_in_text_section) {
304         symbol.is_label = true;
305         if (is_arm) {
306           // Remove mapping symbols in arm.
307           const char* p = (symbol.name.compare(0, linker_prefix.size(), linker_prefix) == 0)
308                               ? symbol.name.c_str() + linker_prefix.size()
309                               : symbol.name.c_str();
310           if (IsArmMappingSymbol(p)) {
311             symbol.is_label = false;
312           }
313         }
314       }
315     }
316 
317     callback(symbol);
318   }
319 }
320 
321 template <class ELFT>
AddSymbolForPltSection(const llvm::object::ELFObjectFile<ELFT> * elf,const std::function<void (const ElfFileSymbol &)> & callback)322 void AddSymbolForPltSection(const llvm::object::ELFObjectFile<ELFT>* elf,
323                             const std::function<void(const ElfFileSymbol&)>& callback) {
324   // We may sample instructions in .plt section if the program
325   // calls functions from shared libraries. Different architectures use
326   // different formats to store .plt section, so it needs a lot of work to match
327   // instructions in .plt section to symbols. As samples in .plt section rarely
328   // happen, and .plt section can hardly be a performance bottleneck, we can
329   // just use a symbol @plt to represent instructions in .plt section.
330   for (auto it = elf->section_begin(); it != elf->section_end(); ++it) {
331     const llvm::object::ELFSectionRef& section_ref = *it;
332     llvm::StringRef section_name;
333     std::error_code err = section_ref.getName(section_name);
334     if (err || section_name != ".plt") {
335       continue;
336     }
337     const auto* shdr = elf->getSection(section_ref.getRawDataRefImpl());
338     if (shdr == nullptr) {
339       return;
340     }
341     ElfFileSymbol symbol;
342     symbol.vaddr = shdr->sh_addr;
343     symbol.len = shdr->sh_size;
344     symbol.is_func = true;
345     symbol.is_label = true;
346     symbol.is_in_text_section = true;
347     symbol.name = "@plt";
348     callback(symbol);
349     return;
350   }
351 }
352 
353 template <class ELFT>
CheckSymbolSections(const llvm::object::ELFObjectFile<ELFT> * elf,bool * has_symtab,bool * has_dynsym)354 void CheckSymbolSections(const llvm::object::ELFObjectFile<ELFT>* elf,
355                          bool* has_symtab, bool* has_dynsym) {
356   *has_symtab = false;
357   *has_dynsym = false;
358   for (auto it = elf->section_begin(); it != elf->section_end(); ++it) {
359     const llvm::object::ELFSectionRef& section_ref = *it;
360     llvm::StringRef section_name;
361     std::error_code err = section_ref.getName(section_name);
362     if (err) {
363       continue;
364     }
365     if (section_name == ".dynsym") {
366       *has_dynsym = true;
367     } else if (section_name == ".symtab") {
368       *has_symtab = true;
369     }
370   }
371 }
372 
373 template <class ELFT>
ParseSymbolsFromELFFile(const llvm::object::ELFObjectFile<ELFT> * elf,const std::function<void (const ElfFileSymbol &)> & callback)374 ElfStatus ParseSymbolsFromELFFile(const llvm::object::ELFObjectFile<ELFT>* elf,
375                                   const std::function<void(const ElfFileSymbol&)>& callback) {
376   auto machine = elf->getELFFile()->getHeader()->e_machine;
377   bool is_arm = (machine == llvm::ELF::EM_ARM || machine == llvm::ELF::EM_AARCH64);
378   AddSymbolForPltSection(elf, callback);
379   // Some applications deliberately ship elf files with broken section tables.
380   // So check the existence of .symtab section and .dynsym section before reading symbols.
381   bool has_symtab;
382   bool has_dynsym;
383   CheckSymbolSections(elf, &has_symtab, &has_dynsym);
384   if (has_symtab && elf->symbol_begin() != elf->symbol_end()) {
385     ReadSymbolTable(elf->symbol_begin(), elf->symbol_end(), callback, is_arm, elf->section_end());
386     return ElfStatus::NO_ERROR;
387   } else if (has_dynsym &&
388       elf->dynamic_symbol_begin()->getRawDataRefImpl() != llvm::object::DataRefImpl()) {
389     ReadSymbolTable(elf->dynamic_symbol_begin(), elf->dynamic_symbol_end(), callback, is_arm,
390                     elf->section_end());
391   }
392   std::string debugdata;
393   ElfStatus result = ReadSectionFromELFFile(elf, ".gnu_debugdata", &debugdata);
394   if (result == ElfStatus::SECTION_NOT_FOUND) {
395     return ElfStatus::NO_SYMBOL_TABLE;
396   } else if (result == ElfStatus::NO_ERROR) {
397     std::string decompressed_data;
398     if (XzDecompress(debugdata, &decompressed_data)) {
399       BinaryWrapper wrapper;
400       result = OpenObjectFileInMemory(decompressed_data.data(), decompressed_data.size(),
401                                       &wrapper);
402       if (result == ElfStatus::NO_ERROR) {
403         if (auto elf = llvm::dyn_cast<llvm::object::ELF32LEObjectFile>(wrapper.obj)) {
404           return ParseSymbolsFromELFFile(elf, callback);
405         } else if (auto elf = llvm::dyn_cast<llvm::object::ELF64LEObjectFile>(wrapper.obj)) {
406           return ParseSymbolsFromELFFile(elf, callback);
407         } else {
408           return ElfStatus::FILE_MALFORMED;
409         }
410       }
411     }
412   }
413   return result;
414 }
415 
MatchBuildId(llvm::object::ObjectFile * obj,const BuildId & expected_build_id)416 ElfStatus MatchBuildId(llvm::object::ObjectFile* obj, const BuildId& expected_build_id) {
417   if (expected_build_id.IsEmpty()) {
418     return ElfStatus::NO_ERROR;
419   }
420   BuildId real_build_id;
421   ElfStatus result = GetBuildIdFromObjectFile(obj, &real_build_id);
422   if (result != ElfStatus::NO_ERROR) {
423     return result;
424   }
425   if (expected_build_id != real_build_id) {
426     return ElfStatus::BUILD_ID_MISMATCH;
427   }
428   return ElfStatus::NO_ERROR;
429 }
430 
ParseSymbolsFromElfFile(const std::string & filename,const BuildId & expected_build_id,const std::function<void (const ElfFileSymbol &)> & callback)431 ElfStatus ParseSymbolsFromElfFile(const std::string& filename,
432                                   const BuildId& expected_build_id,
433                                   const std::function<void(const ElfFileSymbol&)>& callback) {
434   return ParseSymbolsFromEmbeddedElfFile(filename, 0, 0, expected_build_id, callback);
435 }
436 
ParseSymbolsFromEmbeddedElfFile(const std::string & filename,uint64_t file_offset,uint32_t file_size,const BuildId & expected_build_id,const std::function<void (const ElfFileSymbol &)> & callback)437 ElfStatus ParseSymbolsFromEmbeddedElfFile(const std::string& filename, uint64_t file_offset,
438                                      uint32_t file_size, const BuildId& expected_build_id,
439                                      const std::function<void(const ElfFileSymbol&)>& callback) {
440   BinaryWrapper wrapper;
441   ElfStatus result = OpenObjectFile(filename, file_offset, file_size, &wrapper);
442   if (result != ElfStatus::NO_ERROR) {
443     return result;
444   }
445   result = MatchBuildId(wrapper.obj, expected_build_id);
446   if (result != ElfStatus::NO_ERROR) {
447     return result;
448   }
449   if (auto elf = llvm::dyn_cast<llvm::object::ELF32LEObjectFile>(wrapper.obj)) {
450     return ParseSymbolsFromELFFile(elf, callback);
451   } else if (auto elf = llvm::dyn_cast<llvm::object::ELF64LEObjectFile>(wrapper.obj)) {
452     return ParseSymbolsFromELFFile(elf, callback);
453   }
454   return ElfStatus::FILE_MALFORMED;
455 }
456 
ParseSymbolsFromElfFileInMemory(const char * data,size_t size,const std::function<void (const ElfFileSymbol &)> & callback)457 ElfStatus ParseSymbolsFromElfFileInMemory(const char* data, size_t size,
458                                           const std::function<void(const ElfFileSymbol&)>& callback) {
459   BinaryWrapper wrapper;
460   ElfStatus result = OpenObjectFileInMemory(data, size, &wrapper);
461   if (result != ElfStatus::NO_ERROR) {
462     return result;
463   }
464   if (auto elf = llvm::dyn_cast<llvm::object::ELF32LEObjectFile>(wrapper.obj)) {
465     return ParseSymbolsFromELFFile(elf, callback);
466   } else if (auto elf = llvm::dyn_cast<llvm::object::ELF64LEObjectFile>(wrapper.obj)) {
467     return ParseSymbolsFromELFFile(elf, callback);
468   }
469   return ElfStatus::FILE_MALFORMED;
470 }
471 
472 template <class ELFT>
ParseDynamicSymbolsFromELFFile(const llvm::object::ELFObjectFile<ELFT> * elf,const std::function<void (const ElfFileSymbol &)> & callback)473 ElfStatus ParseDynamicSymbolsFromELFFile(const llvm::object::ELFObjectFile<ELFT>* elf,
474                                          const std::function<void(const ElfFileSymbol&)>& callback) {
475   auto machine = elf->getELFFile()->getHeader()->e_machine;
476   bool is_arm = (machine == llvm::ELF::EM_ARM || machine == llvm::ELF::EM_AARCH64);
477   ReadSymbolTable(elf->dynamic_symbol_begin(), elf->dynamic_symbol_end(), callback, is_arm,
478                   elf->section_end());
479   return ElfStatus::NO_ERROR;
480 }
481 
ParseDynamicSymbolsFromElfFile(const std::string & filename,const std::function<void (const ElfFileSymbol &)> & callback)482 ElfStatus ParseDynamicSymbolsFromElfFile(const std::string& filename,
483                                          const std::function<void(const ElfFileSymbol&)>& callback) {
484   BinaryWrapper wrapper;
485   ElfStatus result = OpenObjectFile(filename, 0, 0, &wrapper);
486   if (result != ElfStatus::NO_ERROR) {
487     return result;
488   }
489   if (auto elf = llvm::dyn_cast<llvm::object::ELF32LEObjectFile>(wrapper.obj)) {
490     return ParseDynamicSymbolsFromELFFile(elf, callback);
491   } else if (auto elf = llvm::dyn_cast<llvm::object::ELF64LEObjectFile>(wrapper.obj)) {
492     return ParseDynamicSymbolsFromELFFile(elf, callback);
493   }
494   return ElfStatus::FILE_MALFORMED;
495 }
496 
497 template <class ELFT>
ReadMinExecutableVirtualAddress(const llvm::object::ELFFile<ELFT> * elf,uint64_t * p_vaddr,uint64_t * file_offset)498 ElfStatus ReadMinExecutableVirtualAddress(const llvm::object::ELFFile<ELFT>* elf,
499                                           uint64_t* p_vaddr,
500                                           uint64_t* file_offset) {
501   bool has_vaddr = false;
502   uint64_t min_addr = std::numeric_limits<uint64_t>::max();
503   for (auto it = elf->program_header_begin(); it != elf->program_header_end(); ++it) {
504     if ((it->p_type == llvm::ELF::PT_LOAD) && (it->p_flags & llvm::ELF::PF_X)) {
505       if (it->p_vaddr < min_addr) {
506         min_addr = it->p_vaddr;
507         *file_offset = it->p_offset;
508         has_vaddr = true;
509       }
510     }
511   }
512   if (!has_vaddr) {
513     // JIT symfiles don't have program headers.
514     min_addr = 0;
515     *file_offset = 0;
516   }
517   *p_vaddr = min_addr;
518   return ElfStatus::NO_ERROR;
519 }
520 
ReadMinExecutableVirtualAddressFromElfFile(const std::string & filename,const BuildId & expected_build_id,uint64_t * min_vaddr,uint64_t * file_offset_of_min_vaddr)521 ElfStatus ReadMinExecutableVirtualAddressFromElfFile(const std::string& filename,
522                                                      const BuildId& expected_build_id,
523                                                      uint64_t* min_vaddr,
524                                                      uint64_t* file_offset_of_min_vaddr) {
525   return ReadMinExecutableVirtualAddressFromEmbeddedElfFile(filename, 0, 0, expected_build_id,
526                                                             min_vaddr, file_offset_of_min_vaddr);
527 }
528 
ReadMinExecutableVirtualAddressFromEmbeddedElfFile(const std::string & filename,uint64_t file_offset,uint32_t file_size,const BuildId & expected_build_id,uint64_t * min_vaddr,uint64_t * file_offset_of_min_vaddr)529 ElfStatus ReadMinExecutableVirtualAddressFromEmbeddedElfFile(const std::string& filename,
530                                                              uint64_t file_offset,
531                                                              uint32_t file_size,
532                                                              const BuildId& expected_build_id,
533                                                              uint64_t* min_vaddr,
534                                                              uint64_t* file_offset_of_min_vaddr) {
535   BinaryWrapper wrapper;
536   ElfStatus result = OpenObjectFile(filename, file_offset, file_size, &wrapper);
537   if (result != ElfStatus::NO_ERROR) {
538     return result;
539   }
540   result = MatchBuildId(wrapper.obj, expected_build_id);
541   if (result != ElfStatus::NO_ERROR) {
542     return result;
543   }
544   if (auto elf = llvm::dyn_cast<llvm::object::ELF32LEObjectFile>(wrapper.obj)) {
545     return ReadMinExecutableVirtualAddress(elf->getELFFile(), min_vaddr, file_offset_of_min_vaddr);
546   } else if (auto elf = llvm::dyn_cast<llvm::object::ELF64LEObjectFile>(wrapper.obj)) {
547     return ReadMinExecutableVirtualAddress(elf->getELFFile(), min_vaddr, file_offset_of_min_vaddr);
548   }
549   return ElfStatus::FILE_MALFORMED;
550 }
551 
ReadSectionFromElfFile(const std::string & filename,const std::string & section_name,std::string * content)552 ElfStatus ReadSectionFromElfFile(const std::string& filename, const std::string& section_name,
553                                  std::string* content) {
554   BinaryWrapper wrapper;
555   ElfStatus result = OpenObjectFile(filename, 0, 0, &wrapper);
556   if (result != ElfStatus::NO_ERROR) {
557     return result;
558   }
559   if (auto elf = llvm::dyn_cast<llvm::object::ELF32LEObjectFile>(wrapper.obj)) {
560     return ReadSectionFromELFFile(elf, section_name, content);
561   } else if (auto elf = llvm::dyn_cast<llvm::object::ELF64LEObjectFile>(wrapper.obj)) {
562     return ReadSectionFromELFFile(elf, section_name, content);
563   } else {
564     return ElfStatus::FILE_MALFORMED;
565   }
566 }
567 
568 namespace {
569 
570 template <typename T>
571 class ElfFileImpl {};
572 
573 template <typename ELFT>
574 class ElfFileImpl<llvm::object::ELFFile<ELFT>> : public ElfFile {
575  public:
ElfFileImpl(BinaryWrapper && wrapper,const llvm::object::ELFFile<ELFT> * elf)576   ElfFileImpl(BinaryWrapper&& wrapper, const llvm::object::ELFFile<ELFT>* elf)
577       : wrapper_(std::move(wrapper)), elf_(elf) {}
578 
GetMemoryBuffer()579   llvm::MemoryBuffer* GetMemoryBuffer() override {
580     return wrapper_.buffer.get();
581   }
582 
583  private:
584   BinaryWrapper wrapper_;
585   const llvm::object::ELFFile<ELFT>* elf_;
586 };
587 
588 }  // namespace
589 
590 namespace simpleperf {
591 
Open(const std::string & filename,ElfStatus * status)592 std::unique_ptr<ElfFile> ElfFile::Open(const std::string& filename, ElfStatus* status) {
593   BinaryWrapper wrapper;
594   auto tuple = SplitUrlInApk(filename);
595   if (std::get<0>(tuple)) {
596     EmbeddedElf* elf = ApkInspector::FindElfInApkByName(std::get<1>(tuple), std::get<2>(tuple));
597     if (elf == nullptr) {
598       *status = ElfStatus::FILE_NOT_FOUND;
599     } else {
600       *status = OpenObjectFile(elf->filepath(), elf->entry_offset(), elf->entry_size(), &wrapper);
601     }
602   } else {
603     *status = OpenObjectFile(filename, 0, 0, &wrapper);
604   }
605   if (*status == ElfStatus::NO_ERROR) {
606     if (auto obj = llvm::dyn_cast<llvm::object::ELF32LEObjectFile>(wrapper.obj)) {
607       using elf_t = std::decay_t<decltype(*obj->getELFFile())>;
608       return std::unique_ptr<ElfFile>(
609           new ElfFileImpl<elf_t>(std::move(wrapper), obj->getELFFile()));
610     }
611     if (auto obj = llvm::dyn_cast<llvm::object::ELF64LEObjectFile>(wrapper.obj)) {
612       using elf_t = std::decay_t<decltype(*obj->getELFFile())>;
613       return std::unique_ptr<ElfFile>(
614           new ElfFileImpl<elf_t>(std::move(wrapper), obj->getELFFile()));
615     }
616     *status = ElfStatus::FILE_MALFORMED;
617   }
618   return nullptr;
619 }
620 
621 }  // namespace simpleperf