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