• 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/ELFObjectFile.h>
36 #include <llvm/Object/ObjectFile.h>
37 
38 #pragma clang diagnostic pop
39 
40 #include "JITDebugReader.h"
41 #include "utils.h"
42 
43 namespace simpleperf {
44 
45 const static char* ELF_NOTE_GNU = "GNU";
46 const static int NT_GNU_BUILD_ID = 3;
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 
IsArmMappingSymbol(const char * name)132 bool IsArmMappingSymbol(const char* name) {
133   // Matches ARM ELF mapping symbols (e.g., $a, $d, $t, $x, $x.foo).
134   // See:
135   //   - ARM64 (ELF for the ARM 64-bit Architecture):
136   //   https://github.com/ARM-software/abi-aa/blob/main/aaelf64/aaelf64.rst#mapping-symbols
137   //   - ARM (ELF for the ARM Architecture):
138   //   https://github.com/ARM-software/abi-aa/blob/main/aaelf32/aaelf32.rst#mapping-symbols
139   // Regex: ^\$(a|d|t|x)(\..*)?$
140   return name[0] == '$' && strchr("adtx", name[1]) != nullptr &&
141          (name[2] == '\0' || name[2] == '.');
142 }
143 
IsRISCVMappingSymbol(const char * name)144 bool IsRISCVMappingSymbol(const char* name) {
145   // Mapping symbols in RISC-V, which are described in "RISC-V ABIs Specification", in
146   // https://github.com/riscv-non-isa/riscv-elf-psabi-doc/blob/master/riscv-elf.adoc#mapping-symbol.
147   // It could be $d, $d.<any>, $x, $x.<any>, $x<isa> or $x<isa>.<any>.
148   // We just loosely check the first character is '$' and the second character is 'd' or 'x'.
149   return name[0] == '$' && strchr("dx", name[1]) != nullptr;
150 }
151 
152 namespace {
153 
154 struct BinaryWrapper {
155   std::unique_ptr<llvm::MemoryBuffer> buffer;
156   std::unique_ptr<llvm::object::ObjectFile> obj;
157 };
158 
OpenObjectFile(const std::string & filename,uint64_t file_offset,uint64_t file_size,BinaryWrapper * wrapper)159 static ElfStatus OpenObjectFile(const std::string& filename, uint64_t file_offset,
160                                 uint64_t file_size, BinaryWrapper* wrapper) {
161   if (!IsRegularFile(filename)) {
162     return ElfStatus::FILE_NOT_FOUND;
163   }
164   android::base::unique_fd fd = FileHelper::OpenReadOnly(filename);
165   if (fd == -1) {
166     return ElfStatus::READ_FAILED;
167   }
168   if (file_size == 0) {
169     file_size = GetFileSize(filename);
170     if (file_size == 0) {
171       return ElfStatus::READ_FAILED;
172     }
173   }
174   ElfStatus status = IsValidElfFile(fd, file_offset);
175   if (status != ElfStatus::NO_ERROR) {
176     return status;
177   }
178   auto buffer_or_err = llvm::MemoryBuffer::getFileSlice(filename, file_size, file_offset);
179   if (!buffer_or_err) {
180     return ElfStatus::READ_FAILED;
181   }
182   auto obj_or_err =
183       llvm::object::ObjectFile::createObjectFile(buffer_or_err.get()->getMemBufferRef());
184   if (!obj_or_err) {
185     return ElfStatus::READ_FAILED;
186   }
187   wrapper->buffer = std::move(buffer_or_err.get());
188   wrapper->obj = std::move(obj_or_err.get());
189   return ElfStatus::NO_ERROR;
190 }
191 
OpenObjectFileInMemory(const char * data,size_t size,BinaryWrapper * wrapper)192 static ElfStatus OpenObjectFileInMemory(const char* data, size_t size, BinaryWrapper* wrapper) {
193   auto buffer = llvm::MemoryBuffer::getMemBuffer(llvm::StringRef(data, size));
194   auto obj_or_err = llvm::object::ObjectFile::createObjectFile(buffer->getMemBufferRef());
195   if (!obj_or_err) {
196     return ElfStatus::FILE_MALFORMED;
197   }
198   wrapper->buffer = std::move(buffer);
199   wrapper->obj = std::move(obj_or_err.get());
200   return ElfStatus::NO_ERROR;
201 }
202 
GetSymbolFlags(const llvm::object::ELFSymbolRef & symbol)203 static inline llvm::Expected<uint32_t> GetSymbolFlags(const llvm::object::ELFSymbolRef& symbol) {
204   return symbol.getFlags();
205 }
206 
GetSymbolValue(const llvm::object::ELFSymbolRef & symbol)207 static inline llvm::Expected<uint64_t> GetSymbolValue(const llvm::object::ELFSymbolRef& symbol) {
208   return symbol.getValue();
209 }
210 
GetSectionName(const llvm::object::SectionRef & section)211 static inline llvm::Expected<llvm::StringRef> GetSectionName(
212     const llvm::object::SectionRef& section) {
213   return section.getName();
214 }
215 
GetSectionContents(const llvm::object::SectionRef & section)216 static inline llvm::Expected<llvm::StringRef> GetSectionContents(
217     const llvm::object::SectionRef& section) {
218   return section.getContents();
219 }
220 
221 template <typename ELFT>
GetELFFile(const llvm::object::ELFObjectFile<ELFT> * obj)222 static inline const llvm::object::ELFFile<ELFT>* GetELFFile(
223     const llvm::object::ELFObjectFile<ELFT>* obj) {
224   return &obj->getELFFile();
225 }
226 
227 template <typename ELFT>
GetELFHeader(const llvm::object::ELFFile<ELFT> * elf)228 static inline const typename ELFT::Ehdr& GetELFHeader(const llvm::object::ELFFile<ELFT>* elf) {
229   return elf->getHeader();
230 }
231 
232 template <typename ELFT>
GetELFProgramHeaders(const llvm::object::ELFFile<ELFT> * elf)233 static inline llvm::Expected<typename ELFT::PhdrRange> GetELFProgramHeaders(
234     const llvm::object::ELFFile<ELFT>* elf) {
235   return elf->program_headers();
236 }
237 
238 template <typename ELFT>
GetELFSectionName(const llvm::object::ELFFile<ELFT> * elf,const typename ELFT::Shdr & section_header)239 static inline llvm::Expected<llvm::StringRef> GetELFSectionName(
240     const llvm::object::ELFFile<ELFT>* elf, const typename ELFT::Shdr& section_header) {
241   return elf->getSectionName(section_header);
242 }
243 
ReadSymbolTable(llvm::object::symbol_iterator sym_begin,llvm::object::symbol_iterator sym_end,const std::function<void (const ElfFileSymbol &)> & callback,int machine,const llvm::object::section_iterator & section_end)244 void ReadSymbolTable(llvm::object::symbol_iterator sym_begin, llvm::object::symbol_iterator sym_end,
245                      const std::function<void(const ElfFileSymbol&)>& callback, int machine,
246                      const llvm::object::section_iterator& section_end) {
247   bool is_arm = (machine == llvm::ELF::EM_ARM || machine == llvm::ELF::EM_AARCH64);
248   bool is_riscv = machine == llvm::ELF::EM_RISCV;
249   for (; sym_begin != sym_end; ++sym_begin) {
250     ElfFileSymbol symbol;
251     auto symbol_ref = static_cast<const llvm::object::ELFSymbolRef*>(&*sym_begin);
252     // Exclude undefined symbols, otherwise we may wrongly use them as labels in functions.
253     if (auto flags = GetSymbolFlags(*symbol_ref);
254         !flags || (flags.get() & symbol_ref->SF_Undefined)) {
255       continue;
256     }
257     llvm::Expected<llvm::object::section_iterator> section_it_or_err = symbol_ref->getSection();
258     if (!section_it_or_err) {
259       continue;
260     }
261     // Symbols in .dynsym section don't have associated section.
262     if (section_it_or_err.get() != section_end) {
263       llvm::Expected<llvm::StringRef> section_name = GetSectionName(*section_it_or_err.get());
264       if (!section_name || section_name.get().empty()) {
265         continue;
266       }
267       if (section_name.get() == ".text") {
268         symbol.is_in_text_section = true;
269       }
270     }
271 
272     llvm::Expected<llvm::StringRef> symbol_name_or_err = symbol_ref->getName();
273     if (!symbol_name_or_err || symbol_name_or_err.get().empty()) {
274       continue;
275     }
276 
277     symbol.name = symbol_name_or_err.get();
278     llvm::Expected<uint64_t> symbol_value = GetSymbolValue(*symbol_ref);
279     if (!symbol_value) {
280       continue;
281     }
282     symbol.vaddr = symbol_value.get();
283     if ((symbol.vaddr & 1) != 0 && is_arm) {
284       // Arm sets bit 0 to mark it as thumb code, remove the flag.
285       symbol.vaddr &= ~1;
286     }
287     symbol.len = symbol_ref->getSize();
288     llvm::object::SymbolRef::Type symbol_type = *symbol_ref->getType();
289     if (symbol_type == llvm::object::SymbolRef::ST_Function) {
290       symbol.is_func = true;
291     } else if (symbol_type == llvm::object::SymbolRef::ST_Unknown) {
292       if (symbol.is_in_text_section) {
293         symbol.is_label = true;
294         const char* p = (symbol.name.compare(0, linker_prefix.size(), linker_prefix) == 0)
295                             ? symbol.name.c_str() + linker_prefix.size()
296                             : symbol.name.c_str();
297         // Remove mapping symbols in arm and RISC-V.
298         if ((is_arm && IsArmMappingSymbol(p)) || (is_riscv && IsRISCVMappingSymbol(p))) {
299           symbol.is_label = false;
300         }
301       }
302     }
303 
304     callback(symbol);
305   }
306 }
307 
308 template <class ELFT>
AddSymbolForPltSection(const llvm::object::ELFObjectFile<ELFT> * elf,const std::function<void (const ElfFileSymbol &)> & callback)309 void AddSymbolForPltSection(const llvm::object::ELFObjectFile<ELFT>* elf,
310                             const std::function<void(const ElfFileSymbol&)>& callback) {
311   // We may sample instructions in .plt section if the program
312   // calls functions from shared libraries. Different architectures use
313   // different formats to store .plt section, so it needs a lot of work to match
314   // instructions in .plt section to symbols. As samples in .plt section rarely
315   // happen, and .plt section can hardly be a performance bottleneck, we can
316   // just use a symbol @plt to represent instructions in .plt section.
317   for (auto it = elf->section_begin(); it != elf->section_end(); ++it) {
318     const llvm::object::ELFSectionRef& section_ref = *it;
319     llvm::Expected<llvm::StringRef> section_name = GetSectionName(section_ref);
320     if (!section_name || section_name.get() != ".plt") {
321       continue;
322     }
323     const auto* shdr = elf->getSection(section_ref.getRawDataRefImpl());
324     if (shdr == nullptr) {
325       return;
326     }
327     ElfFileSymbol symbol;
328     symbol.vaddr = shdr->sh_addr;
329     symbol.len = shdr->sh_size;
330     symbol.is_func = true;
331     symbol.is_label = true;
332     symbol.is_in_text_section = true;
333     symbol.name = "@plt";
334     callback(symbol);
335     return;
336   }
337 }
338 
339 template <class ELFT>
CheckSymbolSections(const llvm::object::ELFObjectFile<ELFT> * elf,bool * has_symtab,bool * has_dynsym)340 void CheckSymbolSections(const llvm::object::ELFObjectFile<ELFT>* elf, bool* has_symtab,
341                          bool* has_dynsym) {
342   *has_symtab = false;
343   *has_dynsym = false;
344   for (auto it = elf->section_begin(); it != elf->section_end(); ++it) {
345     const llvm::object::ELFSectionRef& section_ref = *it;
346     llvm::Expected<llvm::StringRef> section_name = GetSectionName(section_ref);
347     if (!section_name) {
348       continue;
349     }
350     if (section_name.get() == ".dynsym") {
351       *has_dynsym = true;
352     } else if (section_name.get() == ".symtab") {
353       *has_symtab = true;
354     }
355   }
356 }
357 
358 template <typename T>
359 class ElfFileImpl {};
360 
361 template <typename ELFT>
362 class ElfFileImpl<llvm::object::ELFObjectFile<ELFT>> : public ElfFile {
363  public:
ElfFileImpl(BinaryWrapper && wrapper,const llvm::object::ELFObjectFile<ELFT> * elf_obj)364   ElfFileImpl(BinaryWrapper&& wrapper, const llvm::object::ELFObjectFile<ELFT>* elf_obj)
365       : wrapper_(std::move(wrapper)), elf_obj_(elf_obj), elf_(GetELFFile(elf_obj_)) {}
366 
Is64Bit()367   bool Is64Bit() override { return GetELFHeader(elf_).getFileClass() == llvm::ELF::ELFCLASS64; }
368 
GetMemoryBuffer()369   llvm::MemoryBuffer* GetMemoryBuffer() override { return wrapper_.buffer.get(); }
370 
GetProgramHeader()371   std::vector<ElfSegment> GetProgramHeader() override {
372     auto program_headers = GetELFProgramHeaders(elf_);
373     if (!program_headers) {
374       return {};
375     }
376     std::vector<ElfSegment> segments(program_headers.get().size());
377     for (size_t i = 0; i < program_headers.get().size(); i++) {
378       const auto& phdr = program_headers.get()[i];
379       segments[i].vaddr = phdr.p_vaddr;
380       segments[i].file_offset = phdr.p_offset;
381       segments[i].file_size = phdr.p_filesz;
382       segments[i].is_executable =
383           (phdr.p_type == llvm::ELF::PT_LOAD) && (phdr.p_flags & llvm::ELF::PF_X);
384       segments[i].is_load = (phdr.p_type == llvm::ELF::PT_LOAD);
385     }
386     return segments;
387   }
388 
GetSectionHeader()389   std::vector<ElfSection> GetSectionHeader() override {
390     auto section_headers_or_err = elf_->sections();
391     if (!section_headers_or_err) {
392       return {};
393     }
394     const auto& section_headers = section_headers_or_err.get();
395     std::vector<ElfSection> sections(section_headers.size());
396     for (size_t i = 0; i < section_headers.size(); i++) {
397       const auto& shdr = section_headers[i];
398       if (auto name = GetELFSectionName(elf_, shdr); name) {
399         sections[i].name = name.get();
400       }
401       sections[i].vaddr = shdr.sh_addr;
402       sections[i].file_offset = shdr.sh_offset;
403       sections[i].size = shdr.sh_size;
404     }
405     return sections;
406   }
407 
GetBuildId(BuildId * build_id)408   ElfStatus GetBuildId(BuildId* build_id) override {
409     llvm::StringRef data = elf_obj_->getData();
410     const char* binary_start = data.data();
411     const char* binary_end = data.data() + data.size();
412     for (auto it = elf_obj_->section_begin(); it != elf_obj_->section_end(); ++it) {
413       const llvm::object::ELFSectionRef& section_ref = *it;
414       if (section_ref.getType() == llvm::ELF::SHT_NOTE) {
415         llvm::Expected<llvm::StringRef> content = GetSectionContents(section_ref);
416         if (!content) {
417           return ElfStatus::NO_BUILD_ID;
418         }
419         const llvm::StringRef& data = content.get();
420         if (data.data() < binary_start || data.data() + data.size() > binary_end) {
421           return ElfStatus::NO_BUILD_ID;
422         }
423         if (GetBuildIdFromNoteSection(data.data(), data.size(), build_id)) {
424           return ElfStatus::NO_ERROR;
425         }
426       }
427     }
428     return ElfStatus::NO_BUILD_ID;
429   }
430 
ParseSymbols(const ParseSymbolCallback & callback)431   ElfStatus ParseSymbols(const ParseSymbolCallback& callback) override {
432     AddSymbolForPltSection(elf_obj_, callback);
433     // Some applications deliberately ship elf files with broken section tables.
434     // So check the existence of .symtab section and .dynsym section before reading symbols.
435     bool has_symtab;
436     bool has_dynsym;
437     CheckSymbolSections(elf_obj_, &has_symtab, &has_dynsym);
438     int machine = GetELFHeader(elf_).e_machine;
439     if (has_symtab && elf_obj_->symbol_begin() != elf_obj_->symbol_end()) {
440       ReadSymbolTable(elf_obj_->symbol_begin(), elf_obj_->symbol_end(), callback, machine,
441                       elf_obj_->section_end());
442       return ElfStatus::NO_ERROR;
443     }
444     if (has_dynsym &&
445         elf_obj_->dynamic_symbol_begin()->getRawDataRefImpl() != llvm::object::DataRefImpl()) {
446       ReadSymbolTable(elf_obj_->dynamic_symbol_begin(), elf_obj_->dynamic_symbol_end(), callback,
447                       machine, elf_obj_->section_end());
448     }
449     std::string debugdata;
450     ElfStatus result = ReadSection(".gnu_debugdata", &debugdata);
451     if (result == ElfStatus::SECTION_NOT_FOUND) {
452       return ElfStatus::NO_SYMBOL_TABLE;
453     }
454     if (result == ElfStatus::NO_ERROR) {
455       std::string decompressed_data;
456       if (XzDecompress(debugdata, &decompressed_data)) {
457         auto debugdata_elf =
458             ElfFile::Open(decompressed_data.data(), decompressed_data.size(), &result);
459         if (debugdata_elf) {
460           return debugdata_elf->ParseSymbols(callback);
461         }
462       }
463     }
464     return result;
465   }
466 
ParseDynamicSymbols(const ParseSymbolCallback & callback)467   void ParseDynamicSymbols(const ParseSymbolCallback& callback) override {
468     ReadSymbolTable(elf_obj_->dynamic_symbol_begin(), elf_obj_->dynamic_symbol_end(), callback,
469                     GetELFHeader(elf_).e_machine, elf_obj_->section_end());
470   }
471 
ReadSection(const std::string & section_name,std::string * content)472   ElfStatus ReadSection(const std::string& section_name, std::string* content) override {
473     for (llvm::object::section_iterator it = elf_obj_->section_begin();
474          it != elf_obj_->section_end(); ++it) {
475       llvm::Expected<llvm::StringRef> name = GetSectionName(*it);
476       if (!name || name.get() != section_name) {
477         continue;
478       }
479       llvm::Expected<llvm::StringRef> data = GetSectionContents(*it);
480       if (!data) {
481         return ElfStatus::READ_FAILED;
482       }
483       *content = data.get();
484       return ElfStatus::NO_ERROR;
485     }
486     return ElfStatus::SECTION_NOT_FOUND;
487   }
488 
ReadMinExecutableVaddr(uint64_t * file_offset)489   uint64_t ReadMinExecutableVaddr(uint64_t* file_offset) {
490     bool has_vaddr = false;
491     uint64_t min_addr = std::numeric_limits<uint64_t>::max();
492     auto program_headers = GetELFProgramHeaders(elf_);
493     if (program_headers) {
494       for (const auto& ph : program_headers.get()) {
495         if ((ph.p_type == llvm::ELF::PT_LOAD) && (ph.p_flags & llvm::ELF::PF_X) &&
496             (ph.p_vaddr < min_addr)) {
497           min_addr = ph.p_vaddr;
498           *file_offset = ph.p_offset;
499           has_vaddr = true;
500         }
501       }
502     }
503     if (!has_vaddr) {
504       // JIT symfiles don't have program headers.
505       min_addr = 0;
506       *file_offset = 0;
507     }
508     return min_addr;
509   }
510 
VaddrToOff(uint64_t vaddr,uint64_t * file_offset)511   bool VaddrToOff(uint64_t vaddr, uint64_t* file_offset) override {
512     auto program_headers = GetELFProgramHeaders(elf_);
513     if (!program_headers) {
514       return false;
515     }
516     for (const auto& ph : program_headers.get()) {
517       if (ph.p_type == llvm::ELF::PT_LOAD && vaddr >= ph.p_vaddr &&
518           vaddr < ph.p_vaddr + ph.p_filesz) {
519         *file_offset = vaddr - ph.p_vaddr + ph.p_offset;
520         return true;
521       }
522     }
523     return false;
524   }
525 
526  private:
527   BinaryWrapper wrapper_;
528   const llvm::object::ELFObjectFile<ELFT>* elf_obj_;
529   const llvm::object::ELFFile<ELFT>* elf_;
530 };
531 
CreateElfFileImpl(BinaryWrapper && wrapper,ElfStatus * status)532 std::unique_ptr<ElfFile> CreateElfFileImpl(BinaryWrapper&& wrapper, ElfStatus* status) {
533   if (auto obj = llvm::dyn_cast<llvm::object::ELF32LEObjectFile>(wrapper.obj.get())) {
534     return std::unique_ptr<ElfFile>(
535         new ElfFileImpl<llvm::object::ELF32LEObjectFile>(std::move(wrapper), obj));
536   }
537   if (auto obj = llvm::dyn_cast<llvm::object::ELF64LEObjectFile>(wrapper.obj.get())) {
538     return std::unique_ptr<ElfFile>(
539         new ElfFileImpl<llvm::object::ELF64LEObjectFile>(std::move(wrapper), obj));
540   }
541   *status = ElfStatus::FILE_MALFORMED;
542   return nullptr;
543 }
544 
545 }  // namespace
546 
Open(const std::string & filename)547 std::unique_ptr<ElfFile> ElfFile::Open(const std::string& filename) {
548   ElfStatus status;
549   auto elf = Open(filename, &status);
550   if (!elf) {
551     LOG(ERROR) << "failed to open " << filename << ": " << status;
552   }
553   return elf;
554 }
555 
Open(const std::string & filename,const BuildId * expected_build_id,ElfStatus * status)556 std::unique_ptr<ElfFile> ElfFile::Open(const std::string& filename,
557                                        const BuildId* expected_build_id, ElfStatus* status) {
558   BinaryWrapper wrapper;
559   auto tuple = SplitUrlInApk(filename);
560   if (std::get<0>(tuple)) {
561     EmbeddedElf* elf = ApkInspector::FindElfInApkByName(std::get<1>(tuple), std::get<2>(tuple));
562     if (elf == nullptr) {
563       *status = ElfStatus::FILE_NOT_FOUND;
564     } else {
565       *status = OpenObjectFile(elf->filepath(), elf->entry_offset(), elf->entry_size(), &wrapper);
566     }
567   } else if (JITDebugReader::IsPathInJITSymFile(filename)) {
568     size_t colon_pos = filename.rfind(':');
569     CHECK_NE(colon_pos, std::string::npos);
570     // path generated by JITDebugReader: app_jit_cache:<file_start>-<file_end>
571     uint64_t file_start;
572     uint64_t file_end;
573     if (sscanf(filename.data() + colon_pos, ":%" PRIu64 "-%" PRIu64, &file_start, &file_end) != 2) {
574       *status = ElfStatus::FILE_NOT_FOUND;
575       return nullptr;
576     }
577     *status =
578         OpenObjectFile(filename.substr(0, colon_pos), file_start, file_end - file_start, &wrapper);
579   } else {
580     *status = OpenObjectFile(filename, 0, 0, &wrapper);
581   }
582   if (*status != ElfStatus::NO_ERROR) {
583     return nullptr;
584   }
585   auto elf = CreateElfFileImpl(std::move(wrapper), status);
586   if (elf && expected_build_id != nullptr && !expected_build_id->IsEmpty()) {
587     BuildId real_build_id;
588     *status = elf->GetBuildId(&real_build_id);
589     if (*status != ElfStatus::NO_ERROR) {
590       return nullptr;
591     }
592     if (*expected_build_id != real_build_id) {
593       *status = ElfStatus::BUILD_ID_MISMATCH;
594       return nullptr;
595     }
596   }
597   return elf;
598 }
599 
Open(const char * data,size_t size,ElfStatus * status)600 std::unique_ptr<ElfFile> ElfFile::Open(const char* data, size_t size, ElfStatus* status) {
601   BinaryWrapper wrapper;
602   *status = OpenObjectFileInMemory(data, size, &wrapper);
603   if (*status != ElfStatus::NO_ERROR) {
604     return nullptr;
605   }
606   return CreateElfFileImpl(std::move(wrapper), status);
607 }
608 
609 }  // namespace simpleperf
610 
611 // LLVM libraries uses ncurses library, but that isn't needed by simpleperf.
612 // So support a naive implementation to avoid depending on ncurses.
setupterm(char *,int,int *)613 __attribute__((weak)) extern "C" int setupterm(char*, int, int*) {
614   return -1;
615 }
616 
set_curterm(struct term *)617 __attribute__((weak)) extern "C" struct term* set_curterm(struct term*) {
618   return nullptr;
619 }
620 
del_curterm(struct term *)621 __attribute__((weak)) extern "C" int del_curterm(struct term*) {
622   return -1;
623 }
624 
tigetnum(char *)625 __attribute__((weak)) extern "C" int tigetnum(char*) {
626   return -1;
627 }
628