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
47 bool IsValidElfFile(int fd) {
48 static const char elf_magic[] = {0x7f, 'E', 'L', 'F'};
50 return android::base::ReadFully(fd, buf, 4) && memcmp(buf, elf_magic, 4) == 0;
53 bool IsValidElfPath(const std::string& filename) {
54 if (!IsRegularFile(filename)) {
57 std::string mode = std::string("rb") + CLOSE_ON_EXEC_MODE;
58 FILE* fp = fopen(filename.c_str(), mode.c_str());
62 bool result = IsValidElfFile(fileno(fp));
67 static bool GetBuildIdFromNoteSection(const char* section, size_t section_size, BuildId* build_id) {
68 const char* p = section;
69 const char* end = p + section_size;
71 CHECK_LE(p + 12, end);
72 size_t namesz = *reinterpret_cast<const uint32_t*>(p);
74 size_t descsz = *reinterpret_cast<const uint32_t*>(p);
76 uint32_t type = *reinterpret_cast<const uint32_t*>(p);
78 namesz = ALIGN(namesz, 4);
79 descsz = ALIGN(descsz, 4);
80 CHECK_LE(p + namesz + descsz, end);
81 if ((type == NT_GNU_BUILD_ID) && (strcmp(p, ELF_NOTE_GNU) == 0)) {
82 *build_id = BuildId(p + namesz, descsz);
90 bool GetBuildIdFromNoteFile(const std::string& filename, BuildId* build_id) {
92 if (!android::base::ReadFileToString(filename, &content)) {
93 LOG(DEBUG) << "can't read note file " << filename;
96 if (GetBuildIdFromNoteSection(content.c_str(), content.size(), build_id) == false) {
97 LOG(DEBUG) << "can't read build_id from note file " << filename;
103 template <class ELFT>
104 bool GetBuildIdFromELFFile(const llvm::object::ELFFile<ELFT>* elf, BuildId* build_id) {
105 for (auto section_iterator = elf->section_begin(); section_iterator != elf->section_end();
106 ++section_iterator) {
107 if (section_iterator->sh_type == llvm::ELF::SHT_NOTE) {
108 auto contents = elf->getSectionContents(&*section_iterator);
109 if (contents.getError()) {
110 LOG(DEBUG) << "read note section error";
113 if (GetBuildIdFromNoteSection(reinterpret_cast<const char*>(contents->data()),
114 contents->size(), build_id)) {
122 static bool GetBuildIdFromObjectFile(llvm::object::ObjectFile* obj, BuildId* build_id) {
124 if (auto elf = llvm::dyn_cast<llvm::object::ELF32LEObjectFile>(obj)) {
125 result = GetBuildIdFromELFFile(elf->getELFFile(), build_id);
126 } else if (auto elf = llvm::dyn_cast<llvm::object::ELF64LEObjectFile>(obj)) {
127 result = GetBuildIdFromELFFile(elf->getELFFile(), build_id);
129 LOG(ERROR) << "unknown elf format in file " << obj->getFileName().data();
133 LOG(DEBUG) << "no build id present in file " << obj->getFileName().data();
139 llvm::object::OwningBinary<llvm::object::Binary> binary;
140 llvm::object::ObjectFile* obj;
142 BinaryRet() : obj(nullptr) {
146 static BinaryRet OpenObjectFile(const std::string& filename, uint64_t file_offset = 0,
147 uint64_t file_size = 0) {
149 FileHelper fhelper = FileHelper::OpenReadOnly(filename);
151 PLOG(DEBUG) << "failed to open " << filename;
154 if (file_size == 0) {
155 file_size = GetFileSize(filename);
156 if (file_size == 0) {
157 PLOG(ERROR) << "failed to get size of file " << filename;
161 auto buffer_or_err = llvm::MemoryBuffer::getOpenFileSlice(fhelper.fd(), filename, file_size, file_offset);
162 if (!buffer_or_err) {
163 LOG(ERROR) << "failed to read " << filename << " [" << file_offset << "-" << (file_offset + file_size)
164 << "]: " << buffer_or_err.getError().message();
167 auto binary_or_err = llvm::object::createBinary(buffer_or_err.get()->getMemBufferRef());
168 if (!binary_or_err) {
169 LOG(ERROR) << filename << " [" << file_offset << "-" << (file_offset + file_size)
170 << "] is not a binary file: " << binary_or_err.getError().message();
173 ret.binary = llvm::object::OwningBinary<llvm::object::Binary>(std::move(binary_or_err.get()),
174 std::move(buffer_or_err.get()));
175 ret.obj = llvm::dyn_cast<llvm::object::ObjectFile>(ret.binary.getBinary());
176 if (ret.obj == nullptr) {
177 LOG(ERROR) << filename << " [" << file_offset << "-" << (file_offset + file_size)
178 << "] is not an object file";
183 bool GetBuildIdFromElfFile(const std::string& filename, BuildId* build_id) {
184 if (!IsValidElfPath(filename)) {
187 bool result = GetBuildIdFromEmbeddedElfFile(filename, 0, 0, build_id);
188 LOG(VERBOSE) << "GetBuildIdFromElfFile(" << filename << ") => " << build_id->ToString();
192 bool GetBuildIdFromEmbeddedElfFile(const std::string& filename, uint64_t file_offset,
193 uint32_t file_size, BuildId* build_id) {
194 BinaryRet ret = OpenObjectFile(filename, file_offset, file_size);
195 if (ret.obj == nullptr) {
198 return GetBuildIdFromObjectFile(ret.obj, build_id);
201 bool IsArmMappingSymbol(const char* name) {
202 // Mapping symbols in arm, which are described in "ELF for ARM Architecture" and
203 // "ELF for ARM 64-bit Architecture". The regular expression to match mapping symbol
204 // is ^\$(a|d|t|x)(\..*)?$
205 return name[0] == '$' && strchr("adtx", name[1]) != nullptr && (name[2] == '\0' || name[2] == '.');
208 template <class ELFT>
209 void ParseSymbolsFromELFFile(const llvm::object::ELFObjectFile<ELFT>* elf_obj,
210 std::function<void(const ElfFileSymbol&)> callback) {
211 auto elf = elf_obj->getELFFile();
212 bool is_arm = (elf->getHeader()->e_machine == llvm::ELF::EM_ARM ||
213 elf->getHeader()->e_machine == llvm::ELF::EM_AARCH64);
214 auto begin = elf_obj->symbol_begin();
215 auto end = elf_obj->symbol_end();
217 begin = elf_obj->dynamic_symbol_begin();
218 end = elf_obj->dynamic_symbol_end();
220 for (; begin != end; ++begin) {
221 ElfFileSymbol symbol;
222 auto elf_symbol = static_cast<const llvm::object::ELFSymbolRef*>(&*begin);
223 auto section_it = elf_symbol->getSection();
227 llvm::StringRef section_name;
228 if (section_it.get()->getName(section_name) || section_name.empty()) {
231 if (section_name.str() == ".text") {
232 symbol.is_in_text_section = true;
235 auto symbol_name = elf_symbol->getName();
236 if (!symbol_name || symbol_name.get().empty()) {
239 symbol.name = symbol_name.get();
240 symbol.vaddr = elf_symbol->getValue();
241 if ((symbol.vaddr & 1) != 0 && is_arm) {
242 // Arm sets bit 0 to mark it as thumb code, remove the flag.
245 symbol.len = elf_symbol->getSize();
246 int type = elf_symbol->getELFType();
247 if (type == llvm::ELF::STT_FUNC) {
248 symbol.is_func = true;
249 } else if (type == llvm::ELF::STT_NOTYPE) {
250 if (symbol.is_in_text_section) {
251 symbol.is_label = true;
253 // Remove mapping symbols in arm.
254 const char* p = (symbol.name.compare(0, linker_prefix.size(), linker_prefix) == 0)
255 ? symbol.name.c_str() + linker_prefix.size()
256 : symbol.name.c_str();
257 if (IsArmMappingSymbol(p)) {
258 symbol.is_label = false;
268 bool MatchBuildId(llvm::object::ObjectFile* obj, const BuildId& expected_build_id,
269 const std::string& debug_filename) {
270 if (expected_build_id.IsEmpty()) {
273 BuildId real_build_id;
274 if (!GetBuildIdFromObjectFile(obj, &real_build_id)) {
277 if (expected_build_id != real_build_id) {
278 LOG(DEBUG) << "build id for " << debug_filename << " mismatch: "
279 << "expected " << expected_build_id.ToString()
280 << ", real " << real_build_id.ToString();
286 bool ParseSymbolsFromElfFile(const std::string& filename, const BuildId& expected_build_id,
287 std::function<void(const ElfFileSymbol&)> callback) {
288 if (!IsValidElfPath(filename)) {
291 return ParseSymbolsFromEmbeddedElfFile(filename, 0, 0, expected_build_id, callback);
294 bool ParseSymbolsFromEmbeddedElfFile(const std::string& filename, uint64_t file_offset,
295 uint32_t file_size, const BuildId& expected_build_id,
296 std::function<void(const ElfFileSymbol&)> callback) {
297 BinaryRet ret = OpenObjectFile(filename, file_offset, file_size);
298 if (ret.obj == nullptr || !MatchBuildId(ret.obj, expected_build_id, filename)) {
301 if (auto elf = llvm::dyn_cast<llvm::object::ELF32LEObjectFile>(ret.obj)) {
302 ParseSymbolsFromELFFile(elf, callback);
303 } else if (auto elf = llvm::dyn_cast<llvm::object::ELF64LEObjectFile>(ret.obj)) {
304 ParseSymbolsFromELFFile(elf, callback);
306 LOG(ERROR) << "unknown elf format in file " << filename;
312 template <class ELFT>
313 bool ReadMinExecutableVirtualAddress(const llvm::object::ELFFile<ELFT>* elf, uint64_t* p_vaddr) {
314 bool has_vaddr = false;
315 uint64_t min_addr = std::numeric_limits<uint64_t>::max();
316 for (auto it = elf->program_header_begin(); it != elf->program_header_end(); ++it) {
317 if ((it->p_type == llvm::ELF::PT_LOAD) && (it->p_flags & llvm::ELF::PF_X)) {
318 if (it->p_vaddr < min_addr) {
319 min_addr = it->p_vaddr;
330 bool ReadMinExecutableVirtualAddressFromElfFile(const std::string& filename,
331 const BuildId& expected_build_id,
332 uint64_t* min_vaddr) {
333 if (!IsValidElfPath(filename)) {
336 BinaryRet ret = OpenObjectFile(filename);
337 if (ret.obj == nullptr || !MatchBuildId(ret.obj, expected_build_id, filename)) {
342 if (auto elf = llvm::dyn_cast<llvm::object::ELF32LEObjectFile>(ret.obj)) {
343 result = ReadMinExecutableVirtualAddress(elf->getELFFile(), min_vaddr);
344 } else if (auto elf = llvm::dyn_cast<llvm::object::ELF64LEObjectFile>(ret.obj)) {
345 result = ReadMinExecutableVirtualAddress(elf->getELFFile(), min_vaddr);
347 LOG(ERROR) << "unknown elf format in file" << filename;
352 LOG(ERROR) << "no program header in file " << filename;
357 template <class ELFT>
358 bool ReadSectionFromELFFile(const llvm::object::ELFFile<ELFT>* elf, const std::string& section_name,
359 std::string* content) {
360 for (auto it = elf->section_begin(); it != elf->section_end(); ++it) {
361 auto name_or_err = elf->getSectionName(&*it);
362 if (name_or_err && *name_or_err == section_name) {
363 auto data_or_err = elf->getSectionContents(&*it);
365 LOG(ERROR) << "failed to read section " << section_name;
368 content->append(data_or_err->begin(), data_or_err->end());
372 LOG(ERROR) << "can't find section " << section_name;
376 bool ReadSectionFromElfFile(const std::string& filename, const std::string& section_name,
377 std::string* content) {
378 if (!IsValidElfPath(filename)) {
381 BinaryRet ret = OpenObjectFile(filename);
382 if (ret.obj == nullptr) {
386 if (auto elf = llvm::dyn_cast<llvm::object::ELF32LEObjectFile>(ret.obj)) {
387 result = ReadSectionFromELFFile(elf->getELFFile(), section_name, content);
388 } else if (auto elf = llvm::dyn_cast<llvm::object::ELF64LEObjectFile>(ret.obj)) {
389 result = ReadSectionFromELFFile(elf->getELFFile(), section_name, content);
391 LOG(ERROR) << "unknown elf format in file" << filename;