| Christopher Ferris | 3958f80 | 2017-02-01 15:44:40 -0800 | [diff] [blame] | 1 | /* | 
|  | 2 | * Copyright (C) 2017 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 <elf.h> | 
|  | 18 | #include <stdint.h> | 
|  | 19 |  | 
|  | 20 | #include <memory> | 
|  | 21 | #include <string> | 
|  | 22 |  | 
|  | 23 | #include "ElfInterface.h" | 
|  | 24 | #include "Memory.h" | 
|  | 25 | #include "Regs.h" | 
|  | 26 |  | 
|  | 27 | template <typename EhdrType, typename PhdrType, typename ShdrType> | 
|  | 28 | bool ElfInterface::ReadAllHeaders() { | 
|  | 29 | EhdrType ehdr; | 
|  | 30 | if (!memory_->Read(0, &ehdr, sizeof(ehdr))) { | 
|  | 31 | return false; | 
|  | 32 | } | 
|  | 33 |  | 
|  | 34 | if (!ReadProgramHeaders<EhdrType, PhdrType>(ehdr)) { | 
|  | 35 | return false; | 
|  | 36 | } | 
|  | 37 | return ReadSectionHeaders<EhdrType, ShdrType>(ehdr); | 
|  | 38 | } | 
|  | 39 |  | 
|  | 40 | template <typename EhdrType, typename PhdrType> | 
|  | 41 | bool ElfInterface::ReadProgramHeaders(const EhdrType& ehdr) { | 
|  | 42 | uint64_t offset = ehdr.e_phoff; | 
|  | 43 | for (size_t i = 0; i < ehdr.e_phnum; i++, offset += ehdr.e_phentsize) { | 
|  | 44 | PhdrType phdr; | 
|  | 45 | if (!memory_->Read(offset, &phdr, &phdr.p_type, sizeof(phdr.p_type))) { | 
|  | 46 | return false; | 
|  | 47 | } | 
|  | 48 |  | 
|  | 49 | if (HandleType(offset, phdr.p_type)) { | 
|  | 50 | continue; | 
|  | 51 | } | 
|  | 52 |  | 
|  | 53 | switch (phdr.p_type) { | 
|  | 54 | case PT_LOAD: | 
|  | 55 | { | 
|  | 56 | // Get the flags first, if this isn't an executable header, ignore it. | 
|  | 57 | if (!memory_->Read(offset, &phdr, &phdr.p_flags, sizeof(phdr.p_flags))) { | 
|  | 58 | return false; | 
|  | 59 | } | 
|  | 60 | if ((phdr.p_flags & PF_X) == 0) { | 
|  | 61 | continue; | 
|  | 62 | } | 
|  | 63 |  | 
|  | 64 | if (!memory_->Read(offset, &phdr, &phdr.p_vaddr, sizeof(phdr.p_vaddr))) { | 
|  | 65 | return false; | 
|  | 66 | } | 
|  | 67 | if (!memory_->Read(offset, &phdr, &phdr.p_offset, sizeof(phdr.p_offset))) { | 
|  | 68 | return false; | 
|  | 69 | } | 
|  | 70 | if (!memory_->Read(offset, &phdr, &phdr.p_memsz, sizeof(phdr.p_memsz))) { | 
|  | 71 | return false; | 
|  | 72 | } | 
|  | 73 | pt_loads_[phdr.p_offset] = LoadInfo{phdr.p_offset, phdr.p_vaddr, | 
|  | 74 | static_cast<size_t>(phdr.p_memsz)}; | 
|  | 75 | if (phdr.p_offset == 0) { | 
|  | 76 | load_bias_ = phdr.p_vaddr; | 
|  | 77 | } | 
|  | 78 | break; | 
|  | 79 | } | 
|  | 80 |  | 
|  | 81 | case PT_GNU_EH_FRAME: | 
|  | 82 | if (!memory_->Read(offset, &phdr, &phdr.p_offset, sizeof(phdr.p_offset))) { | 
|  | 83 | return false; | 
|  | 84 | } | 
|  | 85 | eh_frame_offset_ = phdr.p_offset; | 
|  | 86 | if (!memory_->Read(offset, &phdr, &phdr.p_memsz, sizeof(phdr.p_memsz))) { | 
|  | 87 | return false; | 
|  | 88 | } | 
|  | 89 | eh_frame_size_ = phdr.p_memsz; | 
|  | 90 | break; | 
|  | 91 |  | 
|  | 92 | case PT_DYNAMIC: | 
|  | 93 | if (!memory_->Read(offset, &phdr, &phdr.p_offset, sizeof(phdr.p_offset))) { | 
|  | 94 | return false; | 
|  | 95 | } | 
|  | 96 | dynamic_offset_ = phdr.p_offset; | 
|  | 97 | if (!memory_->Read(offset, &phdr, &phdr.p_memsz, sizeof(phdr.p_memsz))) { | 
|  | 98 | return false; | 
|  | 99 | } | 
|  | 100 | dynamic_size_ = phdr.p_memsz; | 
|  | 101 | break; | 
|  | 102 | } | 
|  | 103 | } | 
|  | 104 | return true; | 
|  | 105 | } | 
|  | 106 |  | 
|  | 107 | template <typename EhdrType, typename ShdrType> | 
|  | 108 | bool ElfInterface::ReadSectionHeaders(const EhdrType& ehdr) { | 
|  | 109 | uint64_t offset = ehdr.e_shoff; | 
|  | 110 | uint64_t sec_offset = 0; | 
|  | 111 | uint64_t sec_size = 0; | 
|  | 112 |  | 
|  | 113 | // Get the location of the section header names. | 
|  | 114 | // If something is malformed in the header table data, we aren't going | 
|  | 115 | // to terminate, we'll simply ignore this part. | 
|  | 116 | ShdrType shdr; | 
|  | 117 | if (ehdr.e_shstrndx < ehdr.e_shnum) { | 
|  | 118 | uint64_t sh_offset = offset + ehdr.e_shstrndx * ehdr.e_shentsize; | 
|  | 119 | if (memory_->Read(sh_offset, &shdr, &shdr.sh_offset, sizeof(shdr.sh_offset)) | 
|  | 120 | && memory_->Read(sh_offset, &shdr, &shdr.sh_size, sizeof(shdr.sh_size))) { | 
|  | 121 | sec_offset = shdr.sh_offset; | 
|  | 122 | sec_size = shdr.sh_size; | 
|  | 123 | } | 
|  | 124 | } | 
|  | 125 |  | 
|  | 126 | // Skip the first header, it's always going to be NULL. | 
|  | 127 | for (size_t i = 1; i < ehdr.e_shnum; i++, offset += ehdr.e_shentsize) { | 
|  | 128 | if (!memory_->Read(offset, &shdr, &shdr.sh_type, sizeof(shdr.sh_type))) { | 
|  | 129 | return false; | 
|  | 130 | } | 
|  | 131 |  | 
|  | 132 | if (shdr.sh_type == SHT_PROGBITS) { | 
|  | 133 | // Look for the .debug_frame and .gnu_debugdata. | 
|  | 134 | if (!memory_->Read(offset, &shdr, &shdr.sh_name, sizeof(shdr.sh_name))) { | 
|  | 135 | return false; | 
|  | 136 | } | 
|  | 137 | if (shdr.sh_name < sec_size) { | 
|  | 138 | std::string name; | 
|  | 139 | if (memory_->ReadString(sec_offset + shdr.sh_name, &name)) { | 
|  | 140 | if (name == ".debug_frame") { | 
|  | 141 | if (memory_->Read(offset, &shdr, &shdr.sh_offset, sizeof(shdr.sh_offset)) | 
|  | 142 | && memory_->Read(offset, &shdr, &shdr.sh_size, sizeof(shdr.sh_size))) { | 
|  | 143 | debug_frame_offset_ = shdr.sh_offset; | 
|  | 144 | debug_frame_size_ = shdr.sh_size; | 
|  | 145 | } | 
|  | 146 | } else if (name == ".gnu_debugdata") { | 
|  | 147 | if (memory_->Read(offset, &shdr, &shdr.sh_offset, sizeof(shdr.sh_offset)) | 
|  | 148 | && memory_->Read(offset, &shdr, &shdr.sh_size, sizeof(shdr.sh_size))) { | 
|  | 149 | gnu_debugdata_offset_ = shdr.sh_offset; | 
|  | 150 | gnu_debugdata_size_ = shdr.sh_size; | 
|  | 151 | } | 
|  | 152 | } | 
|  | 153 | } | 
|  | 154 | } | 
|  | 155 | } | 
|  | 156 | } | 
|  | 157 | return true; | 
|  | 158 | } | 
|  | 159 |  | 
|  | 160 | template <typename DynType> | 
|  | 161 | bool ElfInterface::GetSonameWithTemplate(std::string* soname) { | 
|  | 162 | if (soname_type_ == SONAME_INVALID) { | 
|  | 163 | return false; | 
|  | 164 | } | 
|  | 165 | if (soname_type_ == SONAME_VALID) { | 
|  | 166 | *soname = soname_; | 
|  | 167 | return true; | 
|  | 168 | } | 
|  | 169 |  | 
|  | 170 | soname_type_ = SONAME_INVALID; | 
|  | 171 |  | 
|  | 172 | uint64_t soname_offset = 0; | 
|  | 173 | uint64_t strtab_offset = 0; | 
|  | 174 | uint64_t strtab_size = 0; | 
|  | 175 |  | 
|  | 176 | // Find the soname location from the dynamic headers section. | 
|  | 177 | DynType dyn; | 
|  | 178 | uint64_t offset = dynamic_offset_; | 
|  | 179 | uint64_t max_offset = offset + dynamic_size_; | 
|  | 180 | for (uint64_t offset = dynamic_offset_; offset < max_offset; offset += sizeof(DynType)) { | 
|  | 181 | if (!memory_->Read(offset, &dyn, sizeof(dyn))) { | 
|  | 182 | return false; | 
|  | 183 | } | 
|  | 184 |  | 
|  | 185 | if (dyn.d_tag == DT_STRTAB) { | 
|  | 186 | strtab_offset = dyn.d_un.d_ptr; | 
|  | 187 | } else if (dyn.d_tag == DT_STRSZ) { | 
|  | 188 | strtab_size = dyn.d_un.d_val; | 
|  | 189 | } else if (dyn.d_tag == DT_SONAME) { | 
|  | 190 | soname_offset = dyn.d_un.d_val; | 
|  | 191 | } else if (dyn.d_tag == DT_NULL) { | 
|  | 192 | break; | 
|  | 193 | } | 
|  | 194 | } | 
|  | 195 |  | 
|  | 196 | soname_offset += strtab_offset; | 
|  | 197 | if (soname_offset >= strtab_offset + strtab_size) { | 
|  | 198 | return false; | 
|  | 199 | } | 
|  | 200 | if (!memory_->ReadString(soname_offset, &soname_)) { | 
|  | 201 | return false; | 
|  | 202 | } | 
|  | 203 | soname_type_ = SONAME_VALID; | 
|  | 204 | *soname = soname_; | 
|  | 205 | return true; | 
|  | 206 | } | 
|  | 207 |  | 
|  | 208 | bool ElfInterface::Step(uint64_t, Regs*, Memory*) { | 
|  | 209 | return false; | 
|  | 210 | } | 
|  | 211 |  | 
|  | 212 | // Instantiate all of the needed template functions. | 
|  | 213 | template bool ElfInterface::ReadAllHeaders<Elf32_Ehdr, Elf32_Phdr, Elf32_Shdr>(); | 
|  | 214 | template bool ElfInterface::ReadAllHeaders<Elf64_Ehdr, Elf64_Phdr, Elf64_Shdr>(); | 
|  | 215 |  | 
|  | 216 | template bool ElfInterface::ReadProgramHeaders<Elf32_Ehdr, Elf32_Phdr>(const Elf32_Ehdr&); | 
|  | 217 | template bool ElfInterface::ReadProgramHeaders<Elf64_Ehdr, Elf64_Phdr>(const Elf64_Ehdr&); | 
|  | 218 |  | 
|  | 219 | template bool ElfInterface::ReadSectionHeaders<Elf32_Ehdr, Elf32_Shdr>(const Elf32_Ehdr&); | 
|  | 220 | template bool ElfInterface::ReadSectionHeaders<Elf64_Ehdr, Elf64_Shdr>(const Elf64_Ehdr&); | 
|  | 221 |  | 
|  | 222 | template bool ElfInterface::GetSonameWithTemplate<Elf32_Dyn>(std::string*); | 
|  | 223 | template bool ElfInterface::GetSonameWithTemplate<Elf64_Dyn>(std::string*); |