BaseElf.cpp (6427B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this file, 3 * You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 5 #include "BaseElf.h" 6 #include "Elfxx.h" 7 #include "Logging.h" 8 #include "mozilla/IntegerPrintfMacros.h" 9 #include "mozilla/RefPtr.h" 10 11 using namespace Elf; 12 13 unsigned long BaseElf::Hash(const char* symbol) { 14 const unsigned char* sym = reinterpret_cast<const unsigned char*>(symbol); 15 unsigned long h = 0, g; 16 while (*sym) { 17 h = (h << 4) + *sym++; 18 g = h & 0xf0000000; 19 h ^= g; 20 h ^= g >> 24; 21 } 22 return h; 23 } 24 25 void* BaseElf::GetSymbolPtr(const char* symbol) const { 26 return GetSymbolPtr(symbol, Hash(symbol)); 27 } 28 29 void* BaseElf::GetSymbolPtr(const char* symbol, unsigned long hash) const { 30 const Sym* sym = GetSymbol(symbol, hash); 31 void* ptr = nullptr; 32 if (sym && sym->st_shndx != SHN_UNDEF) ptr = GetPtr(sym->st_value); 33 DEBUG_LOG("BaseElf::GetSymbolPtr(%p [\"%s\"], \"%s\") = %p", 34 reinterpret_cast<const void*>(this), GetPath(), symbol, ptr); 35 return ptr; 36 } 37 38 const Sym* BaseElf::GetSymbol(const char* symbol, unsigned long hash) const { 39 /* Search symbol with the buckets and chains tables. 40 * The hash computed from the symbol name gives an index in the buckets 41 * table. The corresponding value in the bucket table is an index in the 42 * symbols table and in the chains table. 43 * If the corresponding symbol in the symbols table matches, we're done. 44 * Otherwise, the corresponding value in the chains table is a new index 45 * in both tables, which corresponding symbol is tested and so on and so 46 * forth */ 47 size_t bucket = hash % buckets.numElements(); 48 for (size_t y = buckets[bucket]; y != STN_UNDEF; y = chains[y]) { 49 if (strcmp(symbol, strtab.GetStringAt(symtab[y].st_name))) continue; 50 return &symtab[y]; 51 } 52 return nullptr; 53 } 54 55 bool BaseElf::Contains(void* addr) const { return base.Contains(addr); } 56 57 #ifdef __ARM_EABI__ 58 const void* BaseElf::FindExidx(int* pcount) const { 59 if (arm_exidx) { 60 *pcount = arm_exidx.numElements(); 61 return arm_exidx; 62 } 63 *pcount = 0; 64 return nullptr; 65 } 66 #endif 67 68 already_AddRefed<LibHandle> LoadedElf::Create(const char* path, 69 void* base_addr) { 70 DEBUG_LOG("LoadedElf::Create(\"%s\", %p) = ...", path, base_addr); 71 72 uint8_t mapped; 73 /* If the page is not mapped, mincore returns an error. If base_addr is 74 * nullptr, as would happen if the corresponding binary is prelinked with 75 * the prelink look (but not with the android apriori tool), no page being 76 * mapped there (right?), mincore returns an error, too, which makes 77 * prelinked libraries on glibc unsupported. This is not an interesting 78 * use case for now, so don't try supporting that case. 79 */ 80 if (mincore(const_cast<void*>(base_addr), PageSize(), &mapped)) 81 return nullptr; 82 83 RefPtr<LoadedElf> elf = new LoadedElf(path); 84 85 const Ehdr* ehdr = Ehdr::validate(base_addr); 86 if (!ehdr) return nullptr; 87 88 Addr min_vaddr = (Addr)-1; // We want to find the lowest and biggest 89 Addr max_vaddr = 0; // virtual address used by this Elf. 90 const Phdr* dyn = nullptr; 91 #ifdef __ARM_EABI__ 92 const Phdr* arm_exidx_phdr = nullptr; 93 #endif 94 95 Array<Phdr> phdrs(reinterpret_cast<const char*>(ehdr) + ehdr->e_phoff, 96 ehdr->e_phnum); 97 for (auto phdr = phdrs.begin(); phdr < phdrs.end(); ++phdr) { 98 switch (phdr->p_type) { 99 case PT_LOAD: 100 if (phdr->p_vaddr < min_vaddr) min_vaddr = phdr->p_vaddr; 101 if (max_vaddr < phdr->p_vaddr + phdr->p_memsz) 102 max_vaddr = phdr->p_vaddr + phdr->p_memsz; 103 break; 104 case PT_DYNAMIC: 105 dyn = &*phdr; 106 break; 107 #ifdef __ARM_EABI__ 108 case PT_ARM_EXIDX: 109 /* We cannot initialize arm_exidx here 110 because we don't have a base yet */ 111 arm_exidx_phdr = &*phdr; 112 break; 113 #endif 114 } 115 } 116 117 /* If the lowest PT_LOAD virtual address in headers is not 0, then the ELF 118 * is either prelinked or a non-PIE executable. The former case is not 119 * possible, because base_addr would be nullptr and the mincore test above 120 * would already have made us return. 121 * For a non-PIE executable, PT_LOADs contain absolute addresses, so in 122 * practice, this means min_vaddr should be equal to base_addr. max_vaddr 123 * can thus be adjusted accordingly. 124 */ 125 if (min_vaddr != 0) { 126 void* min_vaddr_ptr = 127 reinterpret_cast<void*>(static_cast<uintptr_t>(min_vaddr)); 128 if (min_vaddr_ptr != base_addr) { 129 LOG("%s: %p != %p", elf->GetPath(), min_vaddr_ptr, base_addr); 130 return nullptr; 131 } 132 max_vaddr -= min_vaddr; 133 } 134 if (!dyn) { 135 LOG("%s: No PT_DYNAMIC segment found", elf->GetPath()); 136 return nullptr; 137 } 138 139 elf->base.Assign(base_addr, max_vaddr); 140 141 if (!elf->InitDyn(dyn)) return nullptr; 142 143 #ifdef __ARM_EABI__ 144 if (arm_exidx_phdr) 145 elf->arm_exidx.InitSize(elf->GetPtr(arm_exidx_phdr->p_vaddr), 146 arm_exidx_phdr->p_memsz); 147 #endif 148 149 DEBUG_LOG("LoadedElf::Create(\"%s\", %p) = %p", path, base_addr, 150 static_cast<void*>(elf)); 151 152 ElfLoader::Singleton.Register(elf); 153 return elf.forget(); 154 } 155 156 bool LoadedElf::InitDyn(const Phdr* pt_dyn) { 157 Array<Dyn> dyns; 158 dyns.InitSize(GetPtr<Dyn>(pt_dyn->p_vaddr), pt_dyn->p_filesz); 159 160 size_t symnum = 0; 161 for (auto dyn = dyns.begin(); dyn < dyns.end() && dyn->d_tag; ++dyn) { 162 switch (dyn->d_tag) { 163 case DT_HASH: { 164 DEBUG_LOG("%s 0x%08" PRIxPTR, "DT_HASH", uintptr_t(dyn->d_un.d_val)); 165 const Elf::Word* hash_table_header = GetPtr<Elf::Word>(dyn->d_un.d_ptr); 166 symnum = hash_table_header[1]; 167 buckets.Init(&hash_table_header[2], hash_table_header[0]); 168 chains.Init(&*buckets.end()); 169 } break; 170 case DT_STRTAB: 171 DEBUG_LOG("%s 0x%08" PRIxPTR, "DT_STRTAB", uintptr_t(dyn->d_un.d_val)); 172 strtab.Init(GetPtr(dyn->d_un.d_ptr)); 173 break; 174 case DT_SYMTAB: 175 DEBUG_LOG("%s 0x%08" PRIxPTR, "DT_SYMTAB", uintptr_t(dyn->d_un.d_val)); 176 symtab.Init(GetPtr(dyn->d_un.d_ptr)); 177 break; 178 } 179 } 180 if (!buckets || !symnum) { 181 ERROR("%s: Missing or broken DT_HASH", GetPath()); 182 } else if (!strtab) { 183 ERROR("%s: Missing DT_STRTAB", GetPath()); 184 } else if (!symtab) { 185 ERROR("%s: Missing DT_SYMTAB", GetPath()); 186 } else { 187 return true; 188 } 189 return false; 190 }