blob: db3d242a041a1db3c70185e098315eca124bc7c5 [file] [log] [blame]
Yabin Cui8f622512015-05-05 19:58:07 -07001/*
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"
Than McIntoshf831e6d2016-02-01 19:50:20 -050018#include "read_apk.h"
Yabin Cui8f622512015-05-05 19:58:07 -070019
20#include <stdio.h>
21#include <string.h>
Than McIntoshf831e6d2016-02-01 19:50:20 -050022#include <sys/stat.h>
23#include <sys/types.h>
Yabin Cui547c60e2015-10-12 16:56:05 -070024
Yabin Cui8f622512015-05-05 19:58:07 -070025#include <algorithm>
Yabin Cui547c60e2015-10-12 16:56:05 -070026#include <limits>
27
Elliott Hughes66dd09e2015-12-04 14:00:57 -080028#include <android-base/file.h>
29#include <android-base/logging.h>
Yabin Cui8f622512015-05-05 19:58:07 -070030
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
Yabin Cui9ba4d942020-09-08 16:12:46 -070041#include "JITDebugReader.h"
Yabin Cui8f622512015-05-05 19:58:07 -070042#include "utils.h"
43
Yabin Cuifaa7b922021-01-11 17:35:57 -080044namespace simpleperf {
Yabin Cuia5bdf0a2015-06-22 19:41:39 -070045
Yabin Cuifaa7b922021-01-11 17:35:57 -080046const static char* ELF_NOTE_GNU = "GNU";
47const static int NT_GNU_BUILD_ID = 3;
Yabin Cui02e20332020-03-16 19:38:23 -070048
Yabin Cuidec43c12016-07-29 16:40:40 -070049std::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;
Than McIntoshf831e6d2016-02-01 19:50:20 -050077}
78
Yabin Cui9e43e9f2018-03-09 15:57:13 -080079bool IsValidElfFileMagic(const char* buf, size_t buf_size) {
Yabin Cuidec43c12016-07-29 16:40:40 -070080 static const char elf_magic[] = {0x7f, 'E', 'L', 'F'};
Yabin Cui9e43e9f2018-03-09 15:57:13 -080081 return (buf_size >= 4u && memcmp(buf, elf_magic, 4) == 0);
82}
83
Yabin Cui02e20332020-03-16 19:38:23 -070084ElfStatus IsValidElfFile(int fd, uint64_t file_offset) {
Yabin Cuidec43c12016-07-29 16:40:40 -070085 char buf[4];
Yabin Cui02e20332020-03-16 19:38:23 -070086 if (!android::base::ReadFullyAtOffset(fd, buf, 4, file_offset)) {
Yabin Cuidec43c12016-07-29 16:40:40 -070087 return ElfStatus::READ_FAILED;
88 }
Yabin Cui9e43e9f2018-03-09 15:57:13 -080089 return IsValidElfFileMagic(buf, 4) ? ElfStatus::NO_ERROR : ElfStatus::FILE_MALFORMED;
Yabin Cuidec43c12016-07-29 16:40:40 -070090}
91
Yabin Cuif79a0082016-11-14 11:23:14 -080092bool GetBuildIdFromNoteSection(const char* section, size_t section_size, BuildId* build_id) {
Yabin Cui8f622512015-05-05 19:58:07 -070093 const char* p = section;
94 const char* end = p + section_size;
95 while (p < end) {
Yabin Cuif79a0082016-11-14 11:23:14 -080096 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);
Yabin Cuia7a0e502016-06-15 11:49:23 -0700105 namesz = Align(namesz, 4);
106 descsz = Align(descsz, 4);
Yabin Cuif79a0082016-11-14 11:23:14 -0800107 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 }
Yabin Cui8f622512015-05-05 19:58:07 -0700116 }
117 p += namesz + descsz;
118 }
119 return false;
120}
121
Yabin Cuidec43c12016-07-29 16:40:40 -0700122ElfStatus GetBuildIdFromNoteFile(const std::string& filename, BuildId* build_id) {
Yabin Cui8f622512015-05-05 19:58:07 -0700123 std::string content;
124 if (!android::base::ReadFileToString(filename, &content)) {
Yabin Cuidec43c12016-07-29 16:40:40 -0700125 return ElfStatus::READ_FAILED;
Yabin Cui8f622512015-05-05 19:58:07 -0700126 }
Yabin Cuidec43c12016-07-29 16:40:40 -0700127 if (!GetBuildIdFromNoteSection(content.c_str(), content.size(), build_id)) {
128 return ElfStatus::NO_BUILD_ID;
Yabin Cui8f622512015-05-05 19:58:07 -0700129 }
Yabin Cuidec43c12016-07-29 16:40:40 -0700130 return ElfStatus::NO_ERROR;
Yabin Cui8f622512015-05-05 19:58:07 -0700131}
132
Yabin Cuifaa7b922021-01-11 17:35:57 -0800133bool 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
141namespace {
142
Yabin Cuidec43c12016-07-29 16:40:40 -0700143struct BinaryWrapper {
Yabin Cui02e20332020-03-16 19:38:23 -0700144 std::unique_ptr<llvm::MemoryBuffer> buffer;
145 std::unique_ptr<llvm::object::Binary> binary;
146 llvm::object::ObjectFile* obj = nullptr;
Yabin Cuib1a885b2016-02-14 19:18:02 -0800147};
148
Yabin Cuidec43c12016-07-29 16:40:40 -0700149static ElfStatus OpenObjectFile(const std::string& filename, uint64_t file_offset,
150 uint64_t file_size, BinaryWrapper* wrapper) {
Yabin Cui02e20332020-03-16 19:38:23 -0700151 if (!IsRegularFile(filename)) {
152 return ElfStatus::FILE_NOT_FOUND;
153 }
Yabin Cui2a53ff32018-05-21 17:37:00 -0700154 android::base::unique_fd fd = FileHelper::OpenReadOnly(filename);
155 if (fd == -1) {
Yabin Cuidec43c12016-07-29 16:40:40 -0700156 return ElfStatus::READ_FAILED;
Than McIntoshf831e6d2016-02-01 19:50:20 -0500157 }
Yabin Cuib1a885b2016-02-14 19:18:02 -0800158 if (file_size == 0) {
159 file_size = GetFileSize(filename);
160 if (file_size == 0) {
Yabin Cuidec43c12016-07-29 16:40:40 -0700161 return ElfStatus::READ_FAILED;
Yabin Cuib1a885b2016-02-14 19:18:02 -0800162 }
Than McIntoshf831e6d2016-02-01 19:50:20 -0500163 }
Yabin Cui02e20332020-03-16 19:38:23 -0700164 ElfStatus status = IsValidElfFile(fd, file_offset);
165 if (status != ElfStatus::NO_ERROR) {
166 return status;
167 }
Yabin Cui2a53ff32018-05-21 17:37:00 -0700168 auto buffer_or_err = llvm::MemoryBuffer::getOpenFileSlice(fd, filename, file_size, file_offset);
Yabin Cuib1a885b2016-02-14 19:18:02 -0800169 if (!buffer_or_err) {
Yabin Cuidec43c12016-07-29 16:40:40 -0700170 return ElfStatus::READ_FAILED;
Than McIntoshf831e6d2016-02-01 19:50:20 -0500171 }
Yabin Cuib1a885b2016-02-14 19:18:02 -0800172 auto binary_or_err = llvm::object::createBinary(buffer_or_err.get()->getMemBufferRef());
173 if (!binary_or_err) {
Yabin Cuidec43c12016-07-29 16:40:40 -0700174 return ElfStatus::READ_FAILED;
Yabin Cuib1a885b2016-02-14 19:18:02 -0800175 }
Yabin Cui02e20332020-03-16 19:38:23 -0700176 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());
Yabin Cuidec43c12016-07-29 16:40:40 -0700179 if (wrapper->obj == nullptr) {
180 return ElfStatus::FILE_MALFORMED;
Yabin Cuib1a885b2016-02-14 19:18:02 -0800181 }
Yabin Cuidec43c12016-07-29 16:40:40 -0700182 return ElfStatus::NO_ERROR;
Than McIntoshf831e6d2016-02-01 19:50:20 -0500183}
184
Yabin Cui9e43e9f2018-03-09 15:57:13 -0800185static ElfStatus OpenObjectFileInMemory(const char* data, size_t size, BinaryWrapper* wrapper) {
186 auto buffer = llvm::MemoryBuffer::getMemBuffer(llvm::StringRef(data, size));
Yabin Cui05400532016-03-17 21:18:53 -0700187 auto binary_or_err = llvm::object::createBinary(buffer->getMemBufferRef());
188 if (!binary_or_err) {
Yabin Cuidec43c12016-07-29 16:40:40 -0700189 return ElfStatus::FILE_MALFORMED;
Yabin Cui05400532016-03-17 21:18:53 -0700190 }
Yabin Cui02e20332020-03-16 19:38:23 -0700191 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());
Yabin Cuidec43c12016-07-29 16:40:40 -0700194 if (wrapper->obj == nullptr) {
195 return ElfStatus::FILE_MALFORMED;
Yabin Cui05400532016-03-17 21:18:53 -0700196 }
Yabin Cuidec43c12016-07-29 16:40:40 -0700197 return ElfStatus::NO_ERROR;
Yabin Cui05400532016-03-17 21:18:53 -0700198}
199
Thiébaud Weksteen4848ee02020-10-23 16:06:59 +0200200void ReadSymbolTable(llvm::object::symbol_iterator sym_begin, llvm::object::symbol_iterator sym_end,
201 const std::function<void(const ElfFileSymbol&)>& callback, bool is_arm,
Yabin Cui81d4c492018-08-09 12:06:10 -0700202 const llvm::object::section_iterator& section_end) {
Yabin Cui05400532016-03-17 21:18:53 -0700203 for (; sym_begin != sym_end; ++sym_begin) {
Yabin Cuiec12ed92015-06-08 10:38:10 -0700204 ElfFileSymbol symbol;
Yabin Cui05400532016-03-17 21:18:53 -0700205 auto symbol_ref = static_cast<const llvm::object::ELFSymbolRef*>(&*sym_begin);
Yabin Cui1b276a32019-11-18 17:23:27 -0800206 // 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 }
Pirama Arumuga Nainar0ea82502016-09-16 16:53:25 -0700210 llvm::Expected<llvm::object::section_iterator> section_it_or_err = symbol_ref->getSection();
Yabin Cui05400532016-03-17 21:18:53 -0700211 if (!section_it_or_err) {
Yabin Cuiec12ed92015-06-08 10:38:10 -0700212 continue;
213 }
Yabin Cui81d4c492018-08-09 12:06:10 -0700214 // 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 }
Yabin Cuiec12ed92015-06-08 10:38:10 -0700224
Pirama Arumuga Nainar0ea82502016-09-16 16:53:25 -0700225 llvm::Expected<llvm::StringRef> symbol_name_or_err = symbol_ref->getName();
Yabin Cui05400532016-03-17 21:18:53 -0700226 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();
Yabin Cui547c60e2015-10-12 16:56:05 -0700232 if ((symbol.vaddr & 1) != 0 && is_arm) {
Yabin Cuib3783552015-06-11 11:15:42 -0700233 // Arm sets bit 0 to mark it as thumb code, remove the flag.
Yabin Cui547c60e2015-10-12 16:56:05 -0700234 symbol.vaddr &= ~1;
Yabin Cuib3783552015-06-11 11:15:42 -0700235 }
Yabin Cui05400532016-03-17 21:18:53 -0700236 symbol.len = symbol_ref->getSize();
Pirama Arumuga Nainar0ea82502016-09-16 16:53:25 -0700237 llvm::object::SymbolRef::Type symbol_type = *symbol_ref->getType();
Yabin Cui05400532016-03-17 21:18:53 -0700238 if (symbol_type == llvm::object::SymbolRef::ST_Function) {
Yabin Cuib3783552015-06-11 11:15:42 -0700239 symbol.is_func = true;
Yabin Cui05400532016-03-17 21:18:53 -0700240 } else if (symbol_type == llvm::object::SymbolRef::ST_Unknown) {
Yabin Cuib3783552015-06-11 11:15:42 -0700241 if (symbol.is_in_text_section) {
242 symbol.is_label = true;
Yabin Cui2c17e0d2015-06-11 14:57:21 -0700243 if (is_arm) {
Yabin Cuia5bdf0a2015-06-22 19:41:39 -0700244 // 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)) {
Yabin Cui2c17e0d2015-06-11 14:57:21 -0700249 symbol.is_label = false;
250 }
Yabin Cuib3783552015-06-11 11:15:42 -0700251 }
252 }
253 }
254
Yabin Cuiec12ed92015-06-08 10:38:10 -0700255 callback(symbol);
256 }
Yabin Cuiec12ed92015-06-08 10:38:10 -0700257}
258
Yabin Cui05400532016-03-17 21:18:53 -0700259template <class ELFT>
Yabin Cui5783fa02016-07-06 18:29:00 -0700260void AddSymbolForPltSection(const llvm::object::ELFObjectFile<ELFT>* elf,
Yabin Cui3e4c5952016-07-26 15:03:27 -0700261 const std::function<void(const ElfFileSymbol&)>& callback) {
Yabin Cui5783fa02016-07-06 18:29:00 -0700262 // 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
Yabin Cui5783fa02016-07-06 18:29:00 -0700291template <class ELFT>
Thiébaud Weksteen4848ee02020-10-23 16:06:59 +0200292void CheckSymbolSections(const llvm::object::ELFObjectFile<ELFT>* elf, bool* has_symtab,
293 bool* has_dynsym) {
Yabin Cuie4e13f32017-12-15 11:36:51 -0800294 *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
Yabin Cui02e20332020-03-16 19:38:23 -0700311template <typename T>
312class ElfFileImpl {};
313
314template <typename ELFT>
Yabin Cui3a880452020-06-29 16:37:31 -0700315class ElfFileImpl<llvm::object::ELFObjectFile<ELFT>> : public ElfFile {
Yabin Cui02e20332020-03-16 19:38:23 -0700316 public:
Yabin Cui3a880452020-06-29 16:37:31 -0700317 ElfFileImpl(BinaryWrapper&& wrapper, const llvm::object::ELFObjectFile<ELFT>* elf_obj)
318 : wrapper_(std::move(wrapper)), elf_obj_(elf_obj), elf_(elf_obj->getELFFile()) {}
Yabin Cui02e20332020-03-16 19:38:23 -0700319
Thiébaud Weksteen4848ee02020-10-23 16:06:59 +0200320 bool Is64Bit() override { return elf_->getHeader()->getFileClass() == llvm::ELF::ELFCLASS64; }
Yabin Cui4ad10fb2020-04-01 15:45:48 -0700321
Thiébaud Weksteen4848ee02020-10-23 16:06:59 +0200322 llvm::MemoryBuffer* GetMemoryBuffer() override { return wrapper_.buffer.get(); }
Yabin Cui02e20332020-03-16 19:38:23 -0700323
Yabin Cui4ad10fb2020-04-01 15:45:48 -0700324 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++) {
Yabin Cui7078c672020-11-10 16:24:12 -0800328 const auto& phdr = program_headers[i];
Yabin Cui4ad10fb2020-04-01 15:45:48 -0700329 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);
Yabin Cui4e4cbbc2020-12-14 15:26:19 -0800334 segments[i].is_load = (phdr.p_type == llvm::ELF::PT_LOAD);
Yabin Cui4ad10fb2020-04-01 15:45:48 -0700335 }
336 return segments;
337 }
338
Yabin Cui7078c672020-11-10 16:24:12 -0800339 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;
Yabin Cui16f41ff2021-03-23 14:58:25 -0700353 sections[i].size = shdr.sh_size;
Yabin Cui7078c672020-11-10 16:24:12 -0800354 }
355 return sections;
356 }
357
Yabin Cui3a880452020-06-29 16:37:31 -0700358 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
Yabin Cui01947032020-06-30 14:36:46 -0700379 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
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
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
Yabin Cui90c3b302020-07-01 10:09:16 -0700439 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
Yabin Cuib60b33c2020-07-15 11:58:41 -0700459 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
Yabin Cui02e20332020-03-16 19:38:23 -0700470 private:
471 BinaryWrapper wrapper_;
Yabin Cui3a880452020-06-29 16:37:31 -0700472 const llvm::object::ELFObjectFile<ELFT>* elf_obj_;
Yabin Cui02e20332020-03-16 19:38:23 -0700473 const llvm::object::ELFFile<ELFT>* elf_;
474};
475
Yabin Cui01947032020-06-30 14:36:46 -0700476std::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
Yabin Cui02e20332020-03-16 19:38:23 -0700489} // namespace
490
Yabin Cuib60b33c2020-07-15 11:58:41 -0700491std::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
Yabin Cui01947032020-06-30 14:36:46 -0700500std::unique_ptr<ElfFile> ElfFile::Open(const std::string& filename,
501 const BuildId* expected_build_id, ElfStatus* status) {
Yabin Cui02e20332020-03-16 19:38:23 -0700502 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 }
Yabin Cui9ba4d942020-09-08 16:12:46 -0700511 } else if (JITDebugReader::IsPathInJITSymFile(filename)) {
512 size_t colon_pos = filename.rfind(':');
513 CHECK_NE(colon_pos, std::string::npos);
Yabin Cuie32ed2b2020-07-23 15:30:14 -0700514 // 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);
Yabin Cui02e20332020-03-16 19:38:23 -0700523 } else {
524 *status = OpenObjectFile(filename, 0, 0, &wrapper);
525 }
Yabin Cui01947032020-06-30 14:36:46 -0700526 if (*status != ElfStatus::NO_ERROR) {
527 return nullptr;
Yabin Cui02e20332020-03-16 19:38:23 -0700528 }
Yabin Cui01947032020-06-30 14:36:46 -0700529 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
544std::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);
Yabin Cui02e20332020-03-16 19:38:23 -0700551}
552
Yabin Cuie55f0322020-05-27 16:26:45 -0700553} // namespace simpleperf
554
Yabin Cuie55f0322020-05-27 16:26:45 -0700555// LLVM libraries uses ncurses library, but that isn't needed by simpleperf.
556// So support a naive implementation to avoid depending on ncurses.
Thiébaud Weksteen4848ee02020-10-23 16:06:59 +0200557__attribute__((weak)) extern "C" int setupterm(char*, int, int*) {
Yabin Cuie55f0322020-05-27 16:26:45 -0700558 return -1;
559}
560
Thiébaud Weksteen4848ee02020-10-23 16:06:59 +0200561__attribute__((weak)) extern "C" struct term* set_curterm(struct term*) {
Yabin Cuie55f0322020-05-27 16:26:45 -0700562 return nullptr;
563}
564
Thiébaud Weksteen4848ee02020-10-23 16:06:59 +0200565__attribute__((weak)) extern "C" int del_curterm(struct term*) {
Yabin Cuie55f0322020-05-27 16:26:45 -0700566 return -1;
567}
568
Thiébaud Weksteen4848ee02020-10-23 16:06:59 +0200569__attribute__((weak)) extern "C" int tigetnum(char*) {
Yabin Cuie55f0322020-05-27 16:26:45 -0700570 return -1;
571}