2 * Copyright (C) 2015 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
23 #include <sys/types.h>
28 #include <android-base/file.h>
29 #include <android-base/logging.h>
31 #pragma clang diagnostic push
32 #pragma clang diagnostic ignored "-Wunused-parameter"
34 #include <llvm/ADT/StringRef.h>
35 #include <llvm/Object/Binary.h>
36 #include <llvm/Object/ELFObjectFile.h>
37 #include <llvm/Object/ObjectFile.h>
39 #pragma clang diagnostic pop
43 #define ELF_NOTE_GNU "GNU"
44 #define NT_GNU_BUILD_ID 3
46 std::ostream& operator<<(std::ostream& os, const ElfStatus& status) {
48 case ElfStatus::NO_ERROR:
51 case ElfStatus::FILE_NOT_FOUND:
52 os << "File not found";
54 case ElfStatus::READ_FAILED:
57 case ElfStatus::FILE_MALFORMED:
58 os << "Malformed file";
60 case ElfStatus::NO_SYMBOL_TABLE:
61 os << "No symbol table";
63 case ElfStatus::NO_BUILD_ID:
66 case ElfStatus::BUILD_ID_MISMATCH:
67 os << "Build id mismatch";
69 case ElfStatus::SECTION_NOT_FOUND:
70 os << "Section not found";
76 ElfStatus IsValidElfFile(int fd) {
77 static const char elf_magic[] = {0x7f, 'E', 'L', 'F'};
79 if (!android::base::ReadFully(fd, buf, 4)) {
80 return ElfStatus::READ_FAILED;
82 if (memcmp(buf, elf_magic, 4) != 0) {
83 return ElfStatus::FILE_MALFORMED;
85 return ElfStatus::NO_ERROR;
88 ElfStatus IsValidElfPath(const std::string& filename) {
89 if (!IsRegularFile(filename)) {
90 return ElfStatus::FILE_NOT_FOUND;
92 std::string mode = std::string("rb") + CLOSE_ON_EXEC_MODE;
93 FILE* fp = fopen(filename.c_str(), mode.c_str());
95 return ElfStatus::READ_FAILED;
97 ElfStatus result = IsValidElfFile(fileno(fp));
102 bool GetBuildIdFromNoteSection(const char* section, size_t section_size, BuildId* build_id) {
103 const char* p = section;
104 const char* end = p + section_size;
112 MoveFromBinaryFormat(namesz, p);
113 MoveFromBinaryFormat(descsz, p);
114 MoveFromBinaryFormat(type, p);
115 namesz = Align(namesz, 4);
116 descsz = Align(descsz, 4);
117 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);
127 p += namesz + descsz;
132 ElfStatus GetBuildIdFromNoteFile(const std::string& filename, BuildId* build_id) {
134 if (!android::base::ReadFileToString(filename, &content)) {
135 return ElfStatus::READ_FAILED;
137 if (!GetBuildIdFromNoteSection(content.c_str(), content.size(), build_id)) {
138 return ElfStatus::NO_BUILD_ID;
140 return ElfStatus::NO_ERROR;
143 template <class ELFT>
144 ElfStatus GetBuildIdFromELFFile(const llvm::object::ELFObjectFile<ELFT>* elf, BuildId* build_id) {
145 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)) {
150 return ElfStatus::READ_FAILED;
152 if (GetBuildIdFromNoteSection(data.data(), data.size(), build_id)) {
153 return ElfStatus::NO_ERROR;
157 return ElfStatus::NO_BUILD_ID;
160 static ElfStatus GetBuildIdFromObjectFile(llvm::object::ObjectFile* obj, BuildId* build_id) {
161 if (auto elf = llvm::dyn_cast<llvm::object::ELF32LEObjectFile>(obj)) {
162 return GetBuildIdFromELFFile(elf, build_id);
163 } else if (auto elf = llvm::dyn_cast<llvm::object::ELF64LEObjectFile>(obj)) {
164 return GetBuildIdFromELFFile(elf, build_id);
166 return ElfStatus::FILE_MALFORMED;
169 struct BinaryWrapper {
170 llvm::object::OwningBinary<llvm::object::Binary> binary;
171 llvm::object::ObjectFile* obj;
173 BinaryWrapper() : obj(nullptr) {
177 static ElfStatus OpenObjectFile(const std::string& filename, uint64_t file_offset,
178 uint64_t file_size, BinaryWrapper* wrapper) {
179 FileHelper fhelper = FileHelper::OpenReadOnly(filename);
181 return ElfStatus::READ_FAILED;
183 if (file_size == 0) {
184 file_size = GetFileSize(filename);
185 if (file_size == 0) {
186 return ElfStatus::READ_FAILED;
189 auto buffer_or_err = llvm::MemoryBuffer::getOpenFileSlice(fhelper.fd(), filename, file_size, file_offset);
190 if (!buffer_or_err) {
191 return ElfStatus::READ_FAILED;
193 auto binary_or_err = llvm::object::createBinary(buffer_or_err.get()->getMemBufferRef());
194 if (!binary_or_err) {
195 return ElfStatus::READ_FAILED;
197 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;
203 return ElfStatus::NO_ERROR;
206 static ElfStatus OpenObjectFileFromString(const std::string& s, BinaryWrapper* wrapper) {
207 auto buffer = llvm::MemoryBuffer::getMemBuffer(s);
208 auto binary_or_err = llvm::object::createBinary(buffer->getMemBufferRef());
209 if (!binary_or_err) {
210 return ElfStatus::FILE_MALFORMED;
212 wrapper->binary = llvm::object::OwningBinary<llvm::object::Binary>(std::move(binary_or_err.get()),
214 wrapper->obj = llvm::dyn_cast<llvm::object::ObjectFile>(wrapper->binary.getBinary());
215 if (wrapper->obj == nullptr) {
216 return ElfStatus::FILE_MALFORMED;
218 return ElfStatus::NO_ERROR;
221 ElfStatus GetBuildIdFromElfFile(const std::string& filename, BuildId* build_id) {
222 ElfStatus result = IsValidElfPath(filename);
223 if (result != ElfStatus::NO_ERROR) {
226 return GetBuildIdFromEmbeddedElfFile(filename, 0, 0, build_id);
229 ElfStatus 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) {
236 return GetBuildIdFromObjectFile(wrapper.obj, build_id);
239 template <class ELFT>
240 ElfStatus ReadSectionFromELFFile(const llvm::object::ELFObjectFile<ELFT>* elf, const std::string& section_name,
241 std::string* content) {
242 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) {
247 llvm::StringRef data;
248 std::error_code err = it->getContents(data);
250 return ElfStatus::READ_FAILED;
253 return ElfStatus::NO_ERROR;
255 return ElfStatus::SECTION_NOT_FOUND;
258 bool 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] == '.');
265 void ReadSymbolTable(llvm::object::symbol_iterator sym_begin,
266 llvm::object::symbol_iterator sym_end,
267 const std::function<void(const ElfFileSymbol&)>& callback,
269 for (; sym_begin != sym_end; ++sym_begin) {
270 ElfFileSymbol symbol;
271 auto symbol_ref = static_cast<const llvm::object::ELFSymbolRef*>(&*sym_begin);
272 llvm::Expected<llvm::object::section_iterator> section_it_or_err = symbol_ref->getSection();
273 if (!section_it_or_err) {
277 llvm::StringRef section_name;
278 if (section_it_or_err.get()->getName(section_name) || section_name.empty()) {
281 if (section_name == ".text") {
282 symbol.is_in_text_section = true;
284 llvm::Expected<llvm::StringRef> symbol_name_or_err = symbol_ref->getName();
285 if (!symbol_name_or_err || symbol_name_or_err.get().empty()) {
289 symbol.name = symbol_name_or_err.get();
290 symbol.vaddr = symbol_ref->getValue();
291 if ((symbol.vaddr & 1) != 0 && is_arm) {
292 // Arm sets bit 0 to mark it as thumb code, remove the flag.
295 symbol.len = symbol_ref->getSize();
296 llvm::object::SymbolRef::Type symbol_type = *symbol_ref->getType();
297 if (symbol_type == llvm::object::SymbolRef::ST_Function) {
298 symbol.is_func = true;
299 } else if (symbol_type == llvm::object::SymbolRef::ST_Unknown) {
300 if (symbol.is_in_text_section) {
301 symbol.is_label = true;
303 // 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)) {
308 symbol.is_label = false;
318 template <class ELFT>
319 void AddSymbolForPltSection(const llvm::object::ELFObjectFile<ELFT>* elf,
320 const std::function<void(const ElfFileSymbol&)>& callback) {
321 // 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") {
334 const auto* shdr = elf->getSection(section_ref.getRawDataRefImpl());
335 if (shdr == nullptr) {
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";
350 template <class ELFT>
351 void CheckSymbolSections(const llvm::object::ELFObjectFile<ELFT>* elf,
352 bool* has_symtab, bool* has_dynsym) {
355 for (auto it = elf->section_begin(); it != elf->section_end(); ++it) {
356 const llvm::object::ELFSectionRef& section_ref = *it;
357 llvm::StringRef section_name;
358 std::error_code err = section_ref.getName(section_name);
362 if (section_name == ".dynsym") {
364 } else if (section_name == ".symtab") {
370 template <class ELFT>
371 ElfStatus ParseSymbolsFromELFFile(const llvm::object::ELFObjectFile<ELFT>* elf,
372 const std::function<void(const ElfFileSymbol&)>& callback) {
373 auto machine = elf->getELFFile()->getHeader()->e_machine;
374 bool is_arm = (machine == llvm::ELF::EM_ARM || machine == llvm::ELF::EM_AARCH64);
375 AddSymbolForPltSection(elf, callback);
376 // Some applications deliberately ship elf files with broken section tables.
377 // So check the existence of .symtab section and .dynsym section before reading symbols.
380 CheckSymbolSections(elf, &has_symtab, &has_dynsym);
381 if (has_symtab && elf->symbol_begin() != elf->symbol_end()) {
382 ReadSymbolTable(elf->symbol_begin(), elf->symbol_end(), callback, is_arm);
383 return ElfStatus::NO_ERROR;
384 } else if (has_dynsym &&
385 elf->dynamic_symbol_begin()->getRawDataRefImpl() != llvm::object::DataRefImpl()) {
386 ReadSymbolTable(elf->dynamic_symbol_begin(), elf->dynamic_symbol_end(), callback, is_arm);
388 std::string debugdata;
389 ElfStatus result = ReadSectionFromELFFile(elf, ".gnu_debugdata", &debugdata);
390 if (result == ElfStatus::SECTION_NOT_FOUND) {
391 return ElfStatus::NO_SYMBOL_TABLE;
392 } else if (result == ElfStatus::NO_ERROR) {
393 std::string decompressed_data;
394 if (XzDecompress(debugdata, &decompressed_data)) {
395 BinaryWrapper wrapper;
396 result = OpenObjectFileFromString(decompressed_data, &wrapper);
397 if (result == ElfStatus::NO_ERROR) {
398 if (auto elf = llvm::dyn_cast<llvm::object::ELF32LEObjectFile>(wrapper.obj)) {
399 return ParseSymbolsFromELFFile(elf, callback);
400 } else if (auto elf = llvm::dyn_cast<llvm::object::ELF64LEObjectFile>(wrapper.obj)) {
401 return ParseSymbolsFromELFFile(elf, callback);
403 return ElfStatus::FILE_MALFORMED;
411 ElfStatus MatchBuildId(llvm::object::ObjectFile* obj, const BuildId& expected_build_id) {
412 if (expected_build_id.IsEmpty()) {
413 return ElfStatus::NO_ERROR;
415 BuildId real_build_id;
416 ElfStatus result = GetBuildIdFromObjectFile(obj, &real_build_id);
417 if (result != ElfStatus::NO_ERROR) {
420 if (expected_build_id != real_build_id) {
421 return ElfStatus::BUILD_ID_MISMATCH;
423 return ElfStatus::NO_ERROR;
426 ElfStatus ParseSymbolsFromElfFile(const std::string& filename,
427 const BuildId& expected_build_id,
428 const std::function<void(const ElfFileSymbol&)>& callback) {
429 ElfStatus result = IsValidElfPath(filename);
430 if (result != ElfStatus::NO_ERROR) {
433 return ParseSymbolsFromEmbeddedElfFile(filename, 0, 0, expected_build_id, callback);
436 ElfStatus ParseSymbolsFromEmbeddedElfFile(const std::string& filename, uint64_t file_offset,
437 uint32_t file_size, const BuildId& expected_build_id,
438 const std::function<void(const ElfFileSymbol&)>& callback) {
439 BinaryWrapper wrapper;
440 ElfStatus result = OpenObjectFile(filename, file_offset, file_size, &wrapper);
441 if (result != ElfStatus::NO_ERROR) {
444 result = MatchBuildId(wrapper.obj, expected_build_id);
445 if (result != ElfStatus::NO_ERROR) {
448 if (auto elf = llvm::dyn_cast<llvm::object::ELF32LEObjectFile>(wrapper.obj)) {
449 return ParseSymbolsFromELFFile(elf, callback);
450 } else if (auto elf = llvm::dyn_cast<llvm::object::ELF64LEObjectFile>(wrapper.obj)) {
451 return ParseSymbolsFromELFFile(elf, callback);
453 return ElfStatus::FILE_MALFORMED;
456 template <class ELFT>
457 ElfStatus ReadMinExecutableVirtualAddress(const llvm::object::ELFFile<ELFT>* elf, uint64_t* p_vaddr) {
458 bool has_vaddr = false;
459 uint64_t min_addr = std::numeric_limits<uint64_t>::max();
460 for (auto it = elf->program_header_begin(); it != elf->program_header_end(); ++it) {
461 if ((it->p_type == llvm::ELF::PT_LOAD) && (it->p_flags & llvm::ELF::PF_X)) {
462 if (it->p_vaddr < min_addr) {
463 min_addr = it->p_vaddr;
469 return ElfStatus::FILE_MALFORMED;
472 return ElfStatus::NO_ERROR;
475 ElfStatus ReadMinExecutableVirtualAddressFromElfFile(const std::string& filename,
476 const BuildId& expected_build_id,
477 uint64_t* min_vaddr) {
478 ElfStatus result = IsValidElfPath(filename);
479 if (result != ElfStatus::NO_ERROR) {
482 BinaryWrapper wrapper;
483 result = OpenObjectFile(filename, 0, 0, &wrapper);
484 if (result != ElfStatus::NO_ERROR) {
487 result = MatchBuildId(wrapper.obj, expected_build_id);
488 if (result != ElfStatus::NO_ERROR) {
492 if (auto elf = llvm::dyn_cast<llvm::object::ELF32LEObjectFile>(wrapper.obj)) {
493 return ReadMinExecutableVirtualAddress(elf->getELFFile(), min_vaddr);
494 } else if (auto elf = llvm::dyn_cast<llvm::object::ELF64LEObjectFile>(wrapper.obj)) {
495 return ReadMinExecutableVirtualAddress(elf->getELFFile(), min_vaddr);
497 return ElfStatus::FILE_MALFORMED;
501 ElfStatus ReadSectionFromElfFile(const std::string& filename, const std::string& section_name,
502 std::string* content) {
503 ElfStatus result = IsValidElfPath(filename);
504 if (result != ElfStatus::NO_ERROR) {
507 BinaryWrapper wrapper;
508 result = OpenObjectFile(filename, 0, 0, &wrapper);
509 if (result != ElfStatus::NO_ERROR) {
512 if (auto elf = llvm::dyn_cast<llvm::object::ELF32LEObjectFile>(wrapper.obj)) {
513 return ReadSectionFromELFFile(elf, section_name, content);
514 } else if (auto elf = llvm::dyn_cast<llvm::object::ELF64LEObjectFile>(wrapper.obj)) {
515 return ReadSectionFromELFFile(elf, section_name, content);
517 return ElfStatus::FILE_MALFORMED;