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