BaseElf.cpp 6.3 KB

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