blob: 7e919a99b36fc09f0f0a21ddd702efdad63bbed0 [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 Cui8f622512015-05-05 19:58:07 -070041#include "utils.h"
42
Yabin Cuia5bdf0a2015-06-22 19:41:39 -070043#define ELF_NOTE_GNU "GNU"
44#define NT_GNU_BUILD_ID 3
45
Yabin Cuidec43c12016-07-29 16:40:40 -070046std::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;
Than McIntoshf831e6d2016-02-01 19:50:20 -050074}
75
Yabin Cuidec43c12016-07-29 16:40:40 -070076ElfStatus IsValidElfFile(int fd) {
77 static const char elf_magic[] = {0x7f, 'E', 'L', 'F'};
78 char buf[4];
79 if (!android::base::ReadFully(fd, buf, 4)) {
80 return ElfStatus::READ_FAILED;
81 }
82 if (memcmp(buf, elf_magic, 4) != 0) {
83 return ElfStatus::FILE_MALFORMED;
84 }
85 return ElfStatus::NO_ERROR;
86}
87
88ElfStatus IsValidElfPath(const std::string& filename) {
Yabin Cui797116b2015-12-08 17:43:15 -080089 if (!IsRegularFile(filename)) {
Yabin Cuidec43c12016-07-29 16:40:40 -070090 return ElfStatus::FILE_NOT_FOUND;
Yabin Cui797116b2015-12-08 17:43:15 -080091 }
Yabin Cuiffaa9122016-01-15 15:25:48 -080092 std::string mode = std::string("rb") + CLOSE_ON_EXEC_MODE;
93 FILE* fp = fopen(filename.c_str(), mode.c_str());
Yabin Cuia5b79fd2015-12-08 19:25:13 -080094 if (fp == nullptr) {
Yabin Cuidec43c12016-07-29 16:40:40 -070095 return ElfStatus::READ_FAILED;
Yabin Cuia5b79fd2015-12-08 19:25:13 -080096 }
Yabin Cuidec43c12016-07-29 16:40:40 -070097 ElfStatus result = IsValidElfFile(fileno(fp));
Yabin Cui797116b2015-12-08 17:43:15 -080098 fclose(fp);
Than McIntoshf831e6d2016-02-01 19:50:20 -050099 return result;
Yabin Cui797116b2015-12-08 17:43:15 -0800100}
101
Yabin Cuif79a0082016-11-14 11:23:14 -0800102bool GetBuildIdFromNoteSection(const char* section, size_t section_size, BuildId* build_id) {
Yabin Cui8f622512015-05-05 19:58:07 -0700103 const char* p = section;
104 const char* end = p + section_size;
105 while (p < end) {
Yabin Cuif79a0082016-11-14 11:23:14 -0800106 if (p + 12 >= end) {
107 return false;
108 }
109 uint32_t namesz;
110 uint32_t descsz;
111 uint32_t type;
112 MoveFromBinaryFormat(namesz, p);
113 MoveFromBinaryFormat(descsz, p);
114 MoveFromBinaryFormat(type, p);
Yabin Cuia7a0e502016-06-15 11:49:23 -0700115 namesz = Align(namesz, 4);
116 descsz = Align(descsz, 4);
Yabin Cuif79a0082016-11-14 11:23:14 -0800117 if ((type == NT_GNU_BUILD_ID) && (p < end) && (strcmp(p, ELF_NOTE_GNU) == 0)) {
118 const char* desc_start = p + namesz;
119 const char* desc_end = desc_start + descsz;
120 if (desc_start > p && desc_start < desc_end && desc_end <= end) {
121 *build_id = BuildId(p + namesz, descsz);
122 return true;
123 } else {
124 return false;
125 }
Yabin Cui8f622512015-05-05 19:58:07 -0700126 }
127 p += namesz + descsz;
128 }
129 return false;
130}
131
Yabin Cuidec43c12016-07-29 16:40:40 -0700132ElfStatus GetBuildIdFromNoteFile(const std::string& filename, BuildId* build_id) {
Yabin Cui8f622512015-05-05 19:58:07 -0700133 std::string content;
134 if (!android::base::ReadFileToString(filename, &content)) {
Yabin Cuidec43c12016-07-29 16:40:40 -0700135 return ElfStatus::READ_FAILED;
Yabin Cui8f622512015-05-05 19:58:07 -0700136 }
Yabin Cuidec43c12016-07-29 16:40:40 -0700137 if (!GetBuildIdFromNoteSection(content.c_str(), content.size(), build_id)) {
138 return ElfStatus::NO_BUILD_ID;
Yabin Cui8f622512015-05-05 19:58:07 -0700139 }
Yabin Cuidec43c12016-07-29 16:40:40 -0700140 return ElfStatus::NO_ERROR;
Yabin Cui8f622512015-05-05 19:58:07 -0700141}
142
143template <class ELFT>
Yabin Cuidec43c12016-07-29 16:40:40 -0700144ElfStatus GetBuildIdFromELFFile(const llvm::object::ELFObjectFile<ELFT>* elf, BuildId* build_id) {
Yabin Cui05400532016-03-17 21:18:53 -0700145 for (auto it = elf->section_begin(); it != elf->section_end(); ++it) {
146 const llvm::object::ELFSectionRef& section_ref = *it;
147 if (section_ref.getType() == llvm::ELF::SHT_NOTE) {
148 llvm::StringRef data;
149 if (it->getContents(data)) {
Yabin Cuidec43c12016-07-29 16:40:40 -0700150 return ElfStatus::READ_FAILED;
Yabin Cui8f622512015-05-05 19:58:07 -0700151 }
Dimitry Ivanovae56a5f2016-11-21 14:29:56 -0800152 if (GetBuildIdFromNoteSection(data.data(), data.size(), build_id)) {
Yabin Cuidec43c12016-07-29 16:40:40 -0700153 return ElfStatus::NO_ERROR;
Yabin Cui8f622512015-05-05 19:58:07 -0700154 }
155 }
156 }
Yabin Cuidec43c12016-07-29 16:40:40 -0700157 return ElfStatus::NO_BUILD_ID;
Yabin Cui8f622512015-05-05 19:58:07 -0700158}
159
Yabin Cuidec43c12016-07-29 16:40:40 -0700160static ElfStatus GetBuildIdFromObjectFile(llvm::object::ObjectFile* obj, BuildId* build_id) {
Yabin Cui638c5582015-07-01 16:16:57 -0700161 if (auto elf = llvm::dyn_cast<llvm::object::ELF32LEObjectFile>(obj)) {
Yabin Cuidec43c12016-07-29 16:40:40 -0700162 return GetBuildIdFromELFFile(elf, build_id);
Yabin Cui638c5582015-07-01 16:16:57 -0700163 } else if (auto elf = llvm::dyn_cast<llvm::object::ELF64LEObjectFile>(obj)) {
Yabin Cuidec43c12016-07-29 16:40:40 -0700164 return GetBuildIdFromELFFile(elf, build_id);
Yabin Cui638c5582015-07-01 16:16:57 -0700165 }
Yabin Cuidec43c12016-07-29 16:40:40 -0700166 return ElfStatus::FILE_MALFORMED;
Yabin Cui638c5582015-07-01 16:16:57 -0700167}
168
Yabin Cuidec43c12016-07-29 16:40:40 -0700169struct BinaryWrapper {
Yabin Cuib1a885b2016-02-14 19:18:02 -0800170 llvm::object::OwningBinary<llvm::object::Binary> binary;
171 llvm::object::ObjectFile* obj;
172
Yabin Cuidec43c12016-07-29 16:40:40 -0700173 BinaryWrapper() : obj(nullptr) {
Than McIntoshf831e6d2016-02-01 19:50:20 -0500174 }
Yabin Cuib1a885b2016-02-14 19:18:02 -0800175};
176
Yabin Cuidec43c12016-07-29 16:40:40 -0700177static ElfStatus OpenObjectFile(const std::string& filename, uint64_t file_offset,
178 uint64_t file_size, BinaryWrapper* wrapper) {
Yabin Cuibe7ec662016-03-02 13:56:28 -0800179 FileHelper fhelper = FileHelper::OpenReadOnly(filename);
Yabin Cuib1a885b2016-02-14 19:18:02 -0800180 if (!fhelper) {
Yabin Cuidec43c12016-07-29 16:40:40 -0700181 return ElfStatus::READ_FAILED;
Than McIntoshf831e6d2016-02-01 19:50:20 -0500182 }
Yabin Cuib1a885b2016-02-14 19:18:02 -0800183 if (file_size == 0) {
184 file_size = GetFileSize(filename);
185 if (file_size == 0) {
Yabin Cuidec43c12016-07-29 16:40:40 -0700186 return ElfStatus::READ_FAILED;
Yabin Cuib1a885b2016-02-14 19:18:02 -0800187 }
Than McIntoshf831e6d2016-02-01 19:50:20 -0500188 }
Yabin Cuib1a885b2016-02-14 19:18:02 -0800189 auto buffer_or_err = llvm::MemoryBuffer::getOpenFileSlice(fhelper.fd(), filename, file_size, file_offset);
190 if (!buffer_or_err) {
Yabin Cuidec43c12016-07-29 16:40:40 -0700191 return ElfStatus::READ_FAILED;
Than McIntoshf831e6d2016-02-01 19:50:20 -0500192 }
Yabin Cuib1a885b2016-02-14 19:18:02 -0800193 auto binary_or_err = llvm::object::createBinary(buffer_or_err.get()->getMemBufferRef());
194 if (!binary_or_err) {
Yabin Cuidec43c12016-07-29 16:40:40 -0700195 return ElfStatus::READ_FAILED;
Yabin Cuib1a885b2016-02-14 19:18:02 -0800196 }
Yabin Cuidec43c12016-07-29 16:40:40 -0700197 wrapper->binary = llvm::object::OwningBinary<llvm::object::Binary>(std::move(binary_or_err.get()),
198 std::move(buffer_or_err.get()));
199 wrapper->obj = llvm::dyn_cast<llvm::object::ObjectFile>(wrapper->binary.getBinary());
200 if (wrapper->obj == nullptr) {
201 return ElfStatus::FILE_MALFORMED;
Yabin Cuib1a885b2016-02-14 19:18:02 -0800202 }
Yabin Cuidec43c12016-07-29 16:40:40 -0700203 return ElfStatus::NO_ERROR;
Than McIntoshf831e6d2016-02-01 19:50:20 -0500204}
205
Yabin Cuidec43c12016-07-29 16:40:40 -0700206static ElfStatus OpenObjectFileFromString(const std::string& s, BinaryWrapper* wrapper) {
Yabin Cui05400532016-03-17 21:18:53 -0700207 auto buffer = llvm::MemoryBuffer::getMemBuffer(s);
208 auto binary_or_err = llvm::object::createBinary(buffer->getMemBufferRef());
209 if (!binary_or_err) {
Yabin Cuidec43c12016-07-29 16:40:40 -0700210 return ElfStatus::FILE_MALFORMED;
Yabin Cui05400532016-03-17 21:18:53 -0700211 }
Yabin Cuidec43c12016-07-29 16:40:40 -0700212 wrapper->binary = llvm::object::OwningBinary<llvm::object::Binary>(std::move(binary_or_err.get()),
Yabin Cui05400532016-03-17 21:18:53 -0700213 std::move(buffer));
Yabin Cuidec43c12016-07-29 16:40:40 -0700214 wrapper->obj = llvm::dyn_cast<llvm::object::ObjectFile>(wrapper->binary.getBinary());
215 if (wrapper->obj == nullptr) {
216 return ElfStatus::FILE_MALFORMED;
Yabin Cui05400532016-03-17 21:18:53 -0700217 }
Yabin Cuidec43c12016-07-29 16:40:40 -0700218 return ElfStatus::NO_ERROR;
Yabin Cui05400532016-03-17 21:18:53 -0700219}
220
Yabin Cuidec43c12016-07-29 16:40:40 -0700221ElfStatus GetBuildIdFromElfFile(const std::string& filename, BuildId* build_id) {
222 ElfStatus result = IsValidElfPath(filename);
223 if (result != ElfStatus::NO_ERROR) {
224 return result;
Yabin Cui797116b2015-12-08 17:43:15 -0800225 }
Yabin Cuidec43c12016-07-29 16:40:40 -0700226 return GetBuildIdFromEmbeddedElfFile(filename, 0, 0, build_id);
Yabin Cuib1a885b2016-02-14 19:18:02 -0800227}
228
Yabin Cuidec43c12016-07-29 16:40:40 -0700229ElfStatus GetBuildIdFromEmbeddedElfFile(const std::string& filename, uint64_t file_offset,
230 uint32_t file_size, BuildId* build_id) {
231 BinaryWrapper wrapper;
232 ElfStatus result = OpenObjectFile(filename, file_offset, file_size, &wrapper);
233 if (result != ElfStatus::NO_ERROR) {
234 return result;
Yabin Cui8f622512015-05-05 19:58:07 -0700235 }
Yabin Cuidec43c12016-07-29 16:40:40 -0700236 return GetBuildIdFromObjectFile(wrapper.obj, build_id);
Yabin Cui8f622512015-05-05 19:58:07 -0700237}
Yabin Cuia5bdf0a2015-06-22 19:41:39 -0700238
Yabin Cui05400532016-03-17 21:18:53 -0700239template <class ELFT>
Yabin Cuidec43c12016-07-29 16:40:40 -0700240ElfStatus ReadSectionFromELFFile(const llvm::object::ELFObjectFile<ELFT>* elf, const std::string& section_name,
241 std::string* content) {
Yabin Cui05400532016-03-17 21:18:53 -0700242 for (llvm::object::section_iterator it = elf->section_begin(); it != elf->section_end(); ++it) {
243 llvm::StringRef name;
244 if (it->getName(name) || name != section_name) {
245 continue;
246 }
247 llvm::StringRef data;
248 std::error_code err = it->getContents(data);
249 if (err) {
Yabin Cuidec43c12016-07-29 16:40:40 -0700250 return ElfStatus::READ_FAILED;
Yabin Cui05400532016-03-17 21:18:53 -0700251 }
252 *content = data;
Yabin Cuidec43c12016-07-29 16:40:40 -0700253 return ElfStatus::NO_ERROR;
Yabin Cui05400532016-03-17 21:18:53 -0700254 }
Yabin Cuidec43c12016-07-29 16:40:40 -0700255 return ElfStatus::SECTION_NOT_FOUND;
Yabin Cui05400532016-03-17 21:18:53 -0700256}
257
Yabin Cuia5bdf0a2015-06-22 19:41:39 -0700258bool IsArmMappingSymbol(const char* name) {
259 // Mapping symbols in arm, which are described in "ELF for ARM Architecture" and
260 // "ELF for ARM 64-bit Architecture". The regular expression to match mapping symbol
261 // is ^\$(a|d|t|x)(\..*)?$
262 return name[0] == '$' && strchr("adtx", name[1]) != nullptr && (name[2] == '\0' || name[2] == '.');
263}
264
Yabin Cui05400532016-03-17 21:18:53 -0700265void ReadSymbolTable(llvm::object::symbol_iterator sym_begin,
266 llvm::object::symbol_iterator sym_end,
Yabin Cui3e4c5952016-07-26 15:03:27 -0700267 const std::function<void(const ElfFileSymbol&)>& callback,
Yabin Cui05400532016-03-17 21:18:53 -0700268 bool is_arm) {
269 for (; sym_begin != sym_end; ++sym_begin) {
Yabin Cuiec12ed92015-06-08 10:38:10 -0700270 ElfFileSymbol symbol;
Yabin Cui05400532016-03-17 21:18:53 -0700271 auto symbol_ref = static_cast<const llvm::object::ELFSymbolRef*>(&*sym_begin);
Pirama Arumuga Nainar0ea82502016-09-16 16:53:25 -0700272 llvm::Expected<llvm::object::section_iterator> section_it_or_err = symbol_ref->getSection();
Yabin Cui05400532016-03-17 21:18:53 -0700273 if (!section_it_or_err) {
Yabin Cuiec12ed92015-06-08 10:38:10 -0700274 continue;
275 }
Yabin Cuiec12ed92015-06-08 10:38:10 -0700276
Yabin Cui05400532016-03-17 21:18:53 -0700277 llvm::StringRef section_name;
278 if (section_it_or_err.get()->getName(section_name) || section_name.empty()) {
Yabin Cuiec12ed92015-06-08 10:38:10 -0700279 continue;
280 }
Yabin Cui05400532016-03-17 21:18:53 -0700281 if (section_name == ".text") {
282 symbol.is_in_text_section = true;
283 }
Pirama Arumuga Nainar0ea82502016-09-16 16:53:25 -0700284 llvm::Expected<llvm::StringRef> symbol_name_or_err = symbol_ref->getName();
Yabin Cui05400532016-03-17 21:18:53 -0700285 if (!symbol_name_or_err || symbol_name_or_err.get().empty()) {
286 continue;
287 }
288
289 symbol.name = symbol_name_or_err.get();
290 symbol.vaddr = symbol_ref->getValue();
Yabin Cui547c60e2015-10-12 16:56:05 -0700291 if ((symbol.vaddr & 1) != 0 && is_arm) {
Yabin Cuib3783552015-06-11 11:15:42 -0700292 // Arm sets bit 0 to mark it as thumb code, remove the flag.
Yabin Cui547c60e2015-10-12 16:56:05 -0700293 symbol.vaddr &= ~1;
Yabin Cuib3783552015-06-11 11:15:42 -0700294 }
Yabin Cui05400532016-03-17 21:18:53 -0700295 symbol.len = symbol_ref->getSize();
Pirama Arumuga Nainar0ea82502016-09-16 16:53:25 -0700296 llvm::object::SymbolRef::Type symbol_type = *symbol_ref->getType();
Yabin Cui05400532016-03-17 21:18:53 -0700297 if (symbol_type == llvm::object::SymbolRef::ST_Function) {
Yabin Cuib3783552015-06-11 11:15:42 -0700298 symbol.is_func = true;
Yabin Cui05400532016-03-17 21:18:53 -0700299 } else if (symbol_type == llvm::object::SymbolRef::ST_Unknown) {
Yabin Cuib3783552015-06-11 11:15:42 -0700300 if (symbol.is_in_text_section) {
301 symbol.is_label = true;
Yabin Cui2c17e0d2015-06-11 14:57:21 -0700302 if (is_arm) {
Yabin Cuia5bdf0a2015-06-22 19:41:39 -0700303 // Remove mapping symbols in arm.
304 const char* p = (symbol.name.compare(0, linker_prefix.size(), linker_prefix) == 0)
305 ? symbol.name.c_str() + linker_prefix.size()
306 : symbol.name.c_str();
307 if (IsArmMappingSymbol(p)) {
Yabin Cui2c17e0d2015-06-11 14:57:21 -0700308 symbol.is_label = false;
309 }
Yabin Cuib3783552015-06-11 11:15:42 -0700310 }
311 }
312 }
313
Yabin Cuiec12ed92015-06-08 10:38:10 -0700314 callback(symbol);
315 }
Yabin Cuiec12ed92015-06-08 10:38:10 -0700316}
317
Yabin Cui05400532016-03-17 21:18:53 -0700318template <class ELFT>
Yabin Cui5783fa02016-07-06 18:29:00 -0700319void AddSymbolForPltSection(const llvm::object::ELFObjectFile<ELFT>* elf,
Yabin Cui3e4c5952016-07-26 15:03:27 -0700320 const std::function<void(const ElfFileSymbol&)>& callback) {
Yabin Cui5783fa02016-07-06 18:29:00 -0700321 // We may sample instructions in .plt section if the program
322 // calls functions from shared libraries. Different architectures use
323 // different formats to store .plt section, so it needs a lot of work to match
324 // instructions in .plt section to symbols. As samples in .plt section rarely
325 // happen, and .plt section can hardly be a performance bottleneck, we can
326 // just use a symbol @plt to represent instructions in .plt section.
327 for (auto it = elf->section_begin(); it != elf->section_end(); ++it) {
328 const llvm::object::ELFSectionRef& section_ref = *it;
329 llvm::StringRef section_name;
330 std::error_code err = section_ref.getName(section_name);
331 if (err || section_name != ".plt") {
332 continue;
333 }
334 const auto* shdr = elf->getSection(section_ref.getRawDataRefImpl());
335 if (shdr == nullptr) {
336 return;
337 }
338 ElfFileSymbol symbol;
339 symbol.vaddr = shdr->sh_addr;
340 symbol.len = shdr->sh_size;
341 symbol.is_func = true;
342 symbol.is_label = true;
343 symbol.is_in_text_section = true;
344 symbol.name = "@plt";
345 callback(symbol);
346 return;
347 }
348}
349
Yabin Cui5783fa02016-07-06 18:29:00 -0700350template <class ELFT>
Yabin Cuidec43c12016-07-29 16:40:40 -0700351ElfStatus ParseSymbolsFromELFFile(const llvm::object::ELFObjectFile<ELFT>* elf,
352 const std::function<void(const ElfFileSymbol&)>& callback) {
Yabin Cui05400532016-03-17 21:18:53 -0700353 auto machine = elf->getELFFile()->getHeader()->e_machine;
354 bool is_arm = (machine == llvm::ELF::EM_ARM || machine == llvm::ELF::EM_AARCH64);
Yabin Cuidec43c12016-07-29 16:40:40 -0700355 AddSymbolForPltSection(elf, callback);
Yabin Cui05400532016-03-17 21:18:53 -0700356 if (elf->symbol_begin() != elf->symbol_end()) {
357 ReadSymbolTable(elf->symbol_begin(), elf->symbol_end(), callback, is_arm);
Yabin Cuidec43c12016-07-29 16:40:40 -0700358 return ElfStatus::NO_ERROR;
Yabin Cui05400532016-03-17 21:18:53 -0700359 } else if (elf->dynamic_symbol_begin()->getRawDataRefImpl() != llvm::object::DataRefImpl()) {
360 ReadSymbolTable(elf->dynamic_symbol_begin(), elf->dynamic_symbol_end(), callback, is_arm);
361 }
362 std::string debugdata;
Yabin Cuidec43c12016-07-29 16:40:40 -0700363 ElfStatus result = ReadSectionFromELFFile(elf, ".gnu_debugdata", &debugdata);
364 if (result == ElfStatus::SECTION_NOT_FOUND) {
365 return ElfStatus::NO_SYMBOL_TABLE;
366 } else if (result == ElfStatus::NO_ERROR) {
Yabin Cui05400532016-03-17 21:18:53 -0700367 std::string decompressed_data;
368 if (XzDecompress(debugdata, &decompressed_data)) {
Yabin Cuidec43c12016-07-29 16:40:40 -0700369 BinaryWrapper wrapper;
370 result = OpenObjectFileFromString(decompressed_data, &wrapper);
371 if (result == ElfStatus::NO_ERROR) {
372 if (auto elf = llvm::dyn_cast<llvm::object::ELF32LEObjectFile>(wrapper.obj)) {
373 return ParseSymbolsFromELFFile(elf, callback);
374 } else if (auto elf = llvm::dyn_cast<llvm::object::ELF64LEObjectFile>(wrapper.obj)) {
375 return ParseSymbolsFromELFFile(elf, callback);
376 } else {
377 return ElfStatus::FILE_MALFORMED;
Yabin Cui05400532016-03-17 21:18:53 -0700378 }
379 }
380 }
381 }
Yabin Cuidec43c12016-07-29 16:40:40 -0700382 return result;
Yabin Cui05400532016-03-17 21:18:53 -0700383}
384
Yabin Cuidec43c12016-07-29 16:40:40 -0700385ElfStatus MatchBuildId(llvm::object::ObjectFile* obj, const BuildId& expected_build_id) {
Yabin Cuib1a885b2016-02-14 19:18:02 -0800386 if (expected_build_id.IsEmpty()) {
Yabin Cuidec43c12016-07-29 16:40:40 -0700387 return ElfStatus::NO_ERROR;
Yabin Cuiec12ed92015-06-08 10:38:10 -0700388 }
Yabin Cuib1a885b2016-02-14 19:18:02 -0800389 BuildId real_build_id;
Yabin Cuidec43c12016-07-29 16:40:40 -0700390 ElfStatus result = GetBuildIdFromObjectFile(obj, &real_build_id);
391 if (result != ElfStatus::NO_ERROR) {
392 return result;
Yabin Cuiec12ed92015-06-08 10:38:10 -0700393 }
Yabin Cuib1a885b2016-02-14 19:18:02 -0800394 if (expected_build_id != real_build_id) {
Yabin Cuidec43c12016-07-29 16:40:40 -0700395 return ElfStatus::BUILD_ID_MISMATCH;
Yabin Cuiec12ed92015-06-08 10:38:10 -0700396 }
Yabin Cuidec43c12016-07-29 16:40:40 -0700397 return ElfStatus::NO_ERROR;
Yabin Cui547c60e2015-10-12 16:56:05 -0700398}
399
Yabin Cuidec43c12016-07-29 16:40:40 -0700400ElfStatus ParseSymbolsFromElfFile(const std::string& filename,
401 const BuildId& expected_build_id,
402 const std::function<void(const ElfFileSymbol&)>& callback) {
403 ElfStatus result = IsValidElfPath(filename);
404 if (result != ElfStatus::NO_ERROR) {
405 return result;
Yabin Cui797116b2015-12-08 17:43:15 -0800406 }
Yabin Cuib1a885b2016-02-14 19:18:02 -0800407 return ParseSymbolsFromEmbeddedElfFile(filename, 0, 0, expected_build_id, callback);
408}
409
Yabin Cuidec43c12016-07-29 16:40:40 -0700410ElfStatus ParseSymbolsFromEmbeddedElfFile(const std::string& filename, uint64_t file_offset,
Yabin Cuib1a885b2016-02-14 19:18:02 -0800411 uint32_t file_size, const BuildId& expected_build_id,
Yabin Cui3e4c5952016-07-26 15:03:27 -0700412 const std::function<void(const ElfFileSymbol&)>& callback) {
Yabin Cuidec43c12016-07-29 16:40:40 -0700413 BinaryWrapper wrapper;
414 ElfStatus result = OpenObjectFile(filename, file_offset, file_size, &wrapper);
415 if (result != ElfStatus::NO_ERROR) {
416 return result;
Yabin Cui547c60e2015-10-12 16:56:05 -0700417 }
Yabin Cuidec43c12016-07-29 16:40:40 -0700418 result = MatchBuildId(wrapper.obj, expected_build_id);
419 if (result != ElfStatus::NO_ERROR) {
420 return result;
Yabin Cui638c5582015-07-01 16:16:57 -0700421 }
Yabin Cuidec43c12016-07-29 16:40:40 -0700422 if (auto elf = llvm::dyn_cast<llvm::object::ELF32LEObjectFile>(wrapper.obj)) {
423 return ParseSymbolsFromELFFile(elf, callback);
424 } else if (auto elf = llvm::dyn_cast<llvm::object::ELF64LEObjectFile>(wrapper.obj)) {
425 return ParseSymbolsFromELFFile(elf, callback);
426 }
427 return ElfStatus::FILE_MALFORMED;
Yabin Cuiec12ed92015-06-08 10:38:10 -0700428}
Yabin Cui547c60e2015-10-12 16:56:05 -0700429
430template <class ELFT>
Yabin Cuidec43c12016-07-29 16:40:40 -0700431ElfStatus ReadMinExecutableVirtualAddress(const llvm::object::ELFFile<ELFT>* elf, uint64_t* p_vaddr) {
Yabin Cui547c60e2015-10-12 16:56:05 -0700432 bool has_vaddr = false;
433 uint64_t min_addr = std::numeric_limits<uint64_t>::max();
Yabin Cui07cdff02016-03-09 14:48:52 -0800434 for (auto it = elf->program_header_begin(); it != elf->program_header_end(); ++it) {
Yabin Cui547c60e2015-10-12 16:56:05 -0700435 if ((it->p_type == llvm::ELF::PT_LOAD) && (it->p_flags & llvm::ELF::PF_X)) {
436 if (it->p_vaddr < min_addr) {
437 min_addr = it->p_vaddr;
438 has_vaddr = true;
439 }
440 }
441 }
Yabin Cuidec43c12016-07-29 16:40:40 -0700442 if (!has_vaddr) {
443 return ElfStatus::FILE_MALFORMED;
Yabin Cui547c60e2015-10-12 16:56:05 -0700444 }
Yabin Cuidec43c12016-07-29 16:40:40 -0700445 *p_vaddr = min_addr;
446 return ElfStatus::NO_ERROR;
Yabin Cui547c60e2015-10-12 16:56:05 -0700447}
448
Yabin Cuidec43c12016-07-29 16:40:40 -0700449ElfStatus ReadMinExecutableVirtualAddressFromElfFile(const std::string& filename,
450 const BuildId& expected_build_id,
451 uint64_t* min_vaddr) {
452 ElfStatus result = IsValidElfPath(filename);
453 if (result != ElfStatus::NO_ERROR) {
454 return result;
Yabin Cui797116b2015-12-08 17:43:15 -0800455 }
Yabin Cuidec43c12016-07-29 16:40:40 -0700456 BinaryWrapper wrapper;
457 result = OpenObjectFile(filename, 0, 0, &wrapper);
458 if (result != ElfStatus::NO_ERROR) {
459 return result;
460 }
461 result = MatchBuildId(wrapper.obj, expected_build_id);
462 if (result != ElfStatus::NO_ERROR) {
463 return result;
Yabin Cui547c60e2015-10-12 16:56:05 -0700464 }
465
Yabin Cuidec43c12016-07-29 16:40:40 -0700466 if (auto elf = llvm::dyn_cast<llvm::object::ELF32LEObjectFile>(wrapper.obj)) {
467 return ReadMinExecutableVirtualAddress(elf->getELFFile(), min_vaddr);
468 } else if (auto elf = llvm::dyn_cast<llvm::object::ELF64LEObjectFile>(wrapper.obj)) {
469 return ReadMinExecutableVirtualAddress(elf->getELFFile(), min_vaddr);
Yabin Cui547c60e2015-10-12 16:56:05 -0700470 } else {
Yabin Cuidec43c12016-07-29 16:40:40 -0700471 return ElfStatus::FILE_MALFORMED;
Yabin Cui547c60e2015-10-12 16:56:05 -0700472 }
Yabin Cui547c60e2015-10-12 16:56:05 -0700473}
Yabin Cuibe7ec662016-03-02 13:56:28 -0800474
Yabin Cuidec43c12016-07-29 16:40:40 -0700475ElfStatus ReadSectionFromElfFile(const std::string& filename, const std::string& section_name,
476 std::string* content) {
477 ElfStatus result = IsValidElfPath(filename);
478 if (result != ElfStatus::NO_ERROR) {
479 return result;
Yabin Cuibe7ec662016-03-02 13:56:28 -0800480 }
Yabin Cuidec43c12016-07-29 16:40:40 -0700481 BinaryWrapper wrapper;
482 result = OpenObjectFile(filename, 0, 0, &wrapper);
483 if (result != ElfStatus::NO_ERROR) {
484 return result;
Yabin Cuibe7ec662016-03-02 13:56:28 -0800485 }
Yabin Cuidec43c12016-07-29 16:40:40 -0700486 if (auto elf = llvm::dyn_cast<llvm::object::ELF32LEObjectFile>(wrapper.obj)) {
487 return ReadSectionFromELFFile(elf, section_name, content);
488 } else if (auto elf = llvm::dyn_cast<llvm::object::ELF64LEObjectFile>(wrapper.obj)) {
489 return ReadSectionFromELFFile(elf, section_name, content);
Yabin Cuibe7ec662016-03-02 13:56:28 -0800490 } else {
Yabin Cuidec43c12016-07-29 16:40:40 -0700491 return ElfStatus::FILE_MALFORMED;
Yabin Cuibe7ec662016-03-02 13:56:28 -0800492 }
Yabin Cuibe7ec662016-03-02 13:56:28 -0800493}