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