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 #define LOG_TAG "DEBUG" 18 19 #include <elf.h> 20 #include <stdint.h> 21 #include <stdlib.h> 22 #include <string.h> 23 24 #include <string> 25 26 #include <backtrace/Backtrace.h> 27 #include <android-base/stringprintf.h> 28 #include <log/log.h> 29 30 #include "elf_utils.h" 31 32 #define NOTE_ALIGN(size) ((size + 3) & ~3) 33 34 template <typename HdrType, typename PhdrType, typename NhdrType> 35 static bool get_build_id( 36 Backtrace* backtrace, uintptr_t base_addr, uint8_t* e_ident, std::string* build_id) { 37 HdrType hdr; 38 39 memcpy(&hdr.e_ident[0], e_ident, EI_NIDENT); 40 41 // First read the rest of the header. 42 if (backtrace->Read(base_addr + EI_NIDENT, reinterpret_cast<uint8_t*>(&hdr) + EI_NIDENT, 43 sizeof(HdrType) - EI_NIDENT) != sizeof(HdrType) - EI_NIDENT) { 44 return false; 45 } 46 47 for (size_t i = 0; i < hdr.e_phnum; i++) { 48 PhdrType phdr; 49 if (backtrace->Read(base_addr + hdr.e_phoff + i * hdr.e_phentsize, 50 reinterpret_cast<uint8_t*>(&phdr), sizeof(phdr)) != sizeof(phdr)) { 51 return false; 52 } 53 // Looking for the .note.gnu.build-id note. 54 if (phdr.p_type == PT_NOTE) { 55 size_t hdr_size = phdr.p_filesz; 56 uintptr_t addr = base_addr + phdr.p_offset; 57 while (hdr_size >= sizeof(NhdrType)) { 58 NhdrType nhdr; 59 if (backtrace->Read(addr, reinterpret_cast<uint8_t*>(&nhdr), sizeof(nhdr)) != sizeof(nhdr)) { 60 return false; 61 } 62 addr += sizeof(nhdr); 63 if (nhdr.n_type == NT_GNU_BUILD_ID) { 64 // Skip the name (which is the owner and should be "GNU"). 65 addr += NOTE_ALIGN(nhdr.n_namesz); 66 uint8_t build_id_data[160]; 67 if (nhdr.n_descsz > sizeof(build_id_data)) { 68 ALOGE("Possible corrupted note, desc size value is too large: %u", 69 nhdr.n_descsz); 70 return false; 71 } 72 if (backtrace->Read(addr, build_id_data, nhdr.n_descsz) != nhdr.n_descsz) { 73 return false; 74 } 75 76 build_id->clear(); 77 for (size_t bytes = 0; bytes < nhdr.n_descsz; bytes++) { 78 *build_id += android::base::StringPrintf("%02x", build_id_data[bytes]); 79 } 80 81 return true; 82 } else { 83 // Move past the extra note data. 84 hdr_size -= sizeof(nhdr); 85 size_t skip_bytes = NOTE_ALIGN(nhdr.n_namesz) + NOTE_ALIGN(nhdr.n_descsz); 86 addr += skip_bytes; 87 if (hdr_size < skip_bytes) { 88 break; 89 } 90 hdr_size -= skip_bytes; 91 } 92 } 93 } 94 } 95 return false; 96 } 97 98 bool elf_get_build_id(Backtrace* backtrace, uintptr_t addr, std::string* build_id) { 99 // Read and verify the elf magic number first. 100 uint8_t e_ident[EI_NIDENT]; 101 if (backtrace->Read(addr, e_ident, SELFMAG) != SELFMAG) { 102 return false; 103 } 104 105 if (memcmp(e_ident, ELFMAG, SELFMAG) != 0) { 106 return false; 107 } 108 109 // Read the rest of EI_NIDENT. 110 if (backtrace->Read(addr + SELFMAG, e_ident + SELFMAG, EI_NIDENT - SELFMAG) != EI_NIDENT - SELFMAG) { 111 return false; 112 } 113 114 if (e_ident[EI_CLASS] == ELFCLASS32) { 115 return get_build_id<Elf32_Ehdr, Elf32_Phdr, Elf32_Nhdr>(backtrace, addr, e_ident, build_id); 116 } else if (e_ident[EI_CLASS] == ELFCLASS64) { 117 return get_build_id<Elf64_Ehdr, Elf64_Phdr, Elf64_Nhdr>(backtrace, addr, e_ident, build_id); 118 } 119 120 return false; 121 } 122