disassembler_elf.h 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361
  1. // Copyright 2018 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #ifndef COMPONENTS_ZUCCHINI_DISASSEMBLER_ELF_H_
  5. #define COMPONENTS_ZUCCHINI_DISASSEMBLER_ELF_H_
  6. #include <stdint.h>
  7. #include <algorithm>
  8. #include <deque>
  9. #include <memory>
  10. #include <string>
  11. #include <vector>
  12. #include "base/memory/raw_ptr.h"
  13. #include "components/zucchini/address_translator.h"
  14. #include "components/zucchini/buffer_view.h"
  15. #include "components/zucchini/disassembler.h"
  16. #include "components/zucchini/image_utils.h"
  17. #include "components/zucchini/rel32_finder.h"
  18. #include "components/zucchini/rel32_utils.h"
  19. #include "components/zucchini/reloc_elf.h"
  20. #include "components/zucchini/type_elf.h"
  21. namespace zucchini {
  22. struct ArmReferencePool {
  23. enum : uint8_t {
  24. kPoolReloc,
  25. kPoolAbs32,
  26. kPoolRel32,
  27. };
  28. };
  29. struct AArch32ReferenceType {
  30. enum : uint8_t {
  31. kReloc, // kPoolReloc
  32. kAbs32, // kPoolAbs32
  33. kRel32_A24, // kPoolRel32
  34. kRel32_T8,
  35. kRel32_T11,
  36. kRel32_T20,
  37. kRel32_T24,
  38. kTypeCount
  39. };
  40. };
  41. struct AArch64ReferenceType {
  42. enum : uint8_t {
  43. kReloc, // kPoolReloc
  44. kAbs32, // kPoolAbs32
  45. kRel32_Immd14, // kPoolRel32
  46. kRel32_Immd19,
  47. kRel32_Immd26,
  48. kTypeCount
  49. };
  50. };
  51. struct Elf32Traits {
  52. static constexpr uint16_t kVersion = 1;
  53. static constexpr Bitness kBitness = kBit32;
  54. static constexpr elf::FileClass kIdentificationClass = elf::ELFCLASS32;
  55. using Elf_Shdr = elf::Elf32_Shdr;
  56. using Elf_Phdr = elf::Elf32_Phdr;
  57. using Elf_Ehdr = elf::Elf32_Ehdr;
  58. using Elf_Rel = elf::Elf32_Rel;
  59. using Elf_Rela = elf::Elf32_Rela;
  60. };
  61. // Architecture-specific definitions.
  62. struct Elf32IntelTraits : public Elf32Traits {
  63. static constexpr ExecutableType kExeType = kExeTypeElfX86;
  64. static const char kExeTypeString[];
  65. static constexpr elf::MachineArchitecture kMachineValue = elf::EM_386;
  66. static constexpr uint32_t kRelType = elf::R_386_RELATIVE;
  67. enum : uint32_t { kVAWidth = 4 };
  68. using Rel32FinderUse = Rel32FinderX86;
  69. };
  70. struct ElfAArch32Traits : public Elf32Traits {
  71. static constexpr ExecutableType kExeType = kExeTypeElfAArch32;
  72. static const char kExeTypeString[];
  73. static constexpr elf::MachineArchitecture kMachineValue = elf::EM_ARM;
  74. static constexpr uint32_t kRelType = elf::R_ARM_RELATIVE;
  75. enum : uint32_t { kVAWidth = 4 };
  76. using ArmReferenceType = AArch32ReferenceType;
  77. using Rel32FinderUse = Rel32FinderAArch32;
  78. };
  79. struct Elf64Traits {
  80. static constexpr uint16_t kVersion = 1;
  81. static constexpr Bitness kBitness = kBit64;
  82. static constexpr elf::FileClass kIdentificationClass = elf::ELFCLASS64;
  83. using Elf_Shdr = elf::Elf64_Shdr;
  84. using Elf_Phdr = elf::Elf64_Phdr;
  85. using Elf_Ehdr = elf::Elf64_Ehdr;
  86. using Elf_Rel = elf::Elf64_Rel;
  87. using Elf_Rela = elf::Elf64_Rela;
  88. };
  89. // Architecture-specific definitions.
  90. struct Elf64IntelTraits : public Elf64Traits {
  91. static constexpr ExecutableType kExeType = kExeTypeElfX64;
  92. static const char kExeTypeString[];
  93. static constexpr elf::MachineArchitecture kMachineValue = elf::EM_X86_64;
  94. static constexpr uint32_t kRelType = elf::R_X86_64_RELATIVE;
  95. enum : uint32_t { kVAWidth = 8 };
  96. using Rel32FinderUse = Rel32FinderX64;
  97. };
  98. struct ElfAArch64Traits : public Elf64Traits {
  99. static constexpr ExecutableType kExeType = kExeTypeElfAArch64;
  100. static const char kExeTypeString[];
  101. static constexpr elf::MachineArchitecture kMachineValue = elf::EM_AARCH64;
  102. // TODO(huangs): See if R_AARCH64_GLOB_DAT and R_AARCH64_JUMP_SLOT should be
  103. // used.
  104. static constexpr uint32_t kRelType = elf::R_AARCH64_RELATIVE;
  105. enum : uint32_t { kVAWidth = 8 };
  106. using ArmReferenceType = AArch64ReferenceType;
  107. using Rel32FinderUse = Rel32FinderAArch64;
  108. };
  109. // Decides whether target |offset| is covered by a section in |sorted_headers|.
  110. template <class ELF_SHDR>
  111. bool IsTargetOffsetInElfSectionList(
  112. const std::vector<const ELF_SHDR*>& sorted_headers,
  113. offset_t offset) {
  114. // Use binary search to search in a list of intervals, in a fashion similar to
  115. // AddressTranslator::OffsetToUnit().
  116. auto comp = [](offset_t offset, const ELF_SHDR* header) -> bool {
  117. return offset < header->sh_offset;
  118. };
  119. auto it = std::upper_bound(sorted_headers.begin(), sorted_headers.end(),
  120. offset, comp);
  121. if (it == sorted_headers.begin())
  122. return false;
  123. --it;
  124. // Just check offset without worrying about width, since this is a target.
  125. // Not using RangeCovers() because |sh_offset| and |sh_size| can be 64-bit.
  126. return offset >= (*it)->sh_offset &&
  127. offset - (*it)->sh_offset < (*it)->sh_size;
  128. }
  129. // Disassembler for ELF.
  130. template <class TRAITS>
  131. class DisassemblerElf : public Disassembler {
  132. public:
  133. using Traits = TRAITS;
  134. static constexpr uint16_t kVersion = Traits::kVersion;
  135. // Applies quick checks to determine whether |image| *may* point to the start
  136. // of an executable. Returns true iff the check passes.
  137. static bool QuickDetect(ConstBufferView image);
  138. DisassemblerElf(const DisassemblerElf&) = delete;
  139. const DisassemblerElf& operator=(const DisassemblerElf&) = delete;
  140. ~DisassemblerElf() override;
  141. // Disassembler:
  142. ExecutableType GetExeType() const override;
  143. std::string GetExeTypeString() const override;
  144. std::vector<ReferenceGroup> MakeReferenceGroups() const override = 0;
  145. // Read/Write functions that are common among different architectures.
  146. std::unique_ptr<ReferenceReader> MakeReadRelocs(offset_t lo, offset_t hi);
  147. std::unique_ptr<ReferenceWriter> MakeWriteRelocs(MutableBufferView image);
  148. const AddressTranslator& translator() const { return translator_; }
  149. protected:
  150. friend Disassembler;
  151. DisassemblerElf();
  152. bool Parse(ConstBufferView image) override;
  153. // Returns the supported Elf_Ehdr::e_machine enum.
  154. static constexpr elf::MachineArchitecture supported_architecture() {
  155. return Traits::kMachineValue;
  156. }
  157. // Returns the type to look for in the reloc section.
  158. static constexpr uint32_t supported_relocation_type() {
  159. return Traits::kRelType;
  160. }
  161. // Performs architecture-specific parsing of an executable section, to extract
  162. // rel32 references.
  163. virtual void ParseExecSection(const typename Traits::Elf_Shdr& section) = 0;
  164. // Processes rel32 data after they are extracted from executable sections.
  165. virtual void PostProcessRel32() = 0;
  166. // Parses ELF header and section headers, and performs basic validation.
  167. // Returns whether parsing was successful.
  168. bool ParseHeader();
  169. // Extracts and stores section headers that we need.
  170. void ExtractInterestingSectionHeaders();
  171. // Parsing functions that extract references from various sections.
  172. void GetAbs32FromRelocSections();
  173. void GetRel32FromCodeSections();
  174. void ParseSections();
  175. // Main ELF header.
  176. raw_ptr<const typename Traits::Elf_Ehdr> header_ = nullptr;
  177. // Section header table, ordered by section id.
  178. elf::Elf32_Half sections_count_ = 0;
  179. raw_ptr<const typename Traits::Elf_Shdr> sections_ = nullptr;
  180. // Program header table.
  181. elf::Elf32_Half segments_count_ = 0;
  182. raw_ptr<const typename Traits::Elf_Phdr> segments_ = nullptr;
  183. // Bit fields to store the role each section may play.
  184. std::vector<int> section_judgements_;
  185. // Translator between offsets and RVAs.
  186. AddressTranslator translator_;
  187. // Identity translator for abs32 translation.
  188. AddressTranslator identity_translator_;
  189. // Extracted relocation section dimensions data, sorted by file offsets.
  190. std::vector<SectionDimensionsElf> reloc_section_dims_;
  191. // Headers of executable sections, sorted by file offsets of the data each
  192. // header points to.
  193. std::vector<const typename Traits::Elf_Shdr*> exec_headers_;
  194. // Sorted file offsets of abs32 locations.
  195. std::deque<offset_t> abs32_locations_;
  196. };
  197. // Disassembler for ELF with Intel architectures.
  198. template <class TRAITS>
  199. class DisassemblerElfIntel : public DisassemblerElf<TRAITS> {
  200. public:
  201. using Traits = TRAITS;
  202. enum ReferenceType : uint8_t { kReloc, kAbs32, kRel32, kTypeCount };
  203. DisassemblerElfIntel();
  204. DisassemblerElfIntel(const DisassemblerElfIntel&) = delete;
  205. const DisassemblerElfIntel& operator=(const DisassemblerElfIntel&) = delete;
  206. ~DisassemblerElfIntel() override;
  207. // Disassembler:
  208. std::vector<ReferenceGroup> MakeReferenceGroups() const override;
  209. // DisassemblerElf:
  210. void ParseExecSection(const typename Traits::Elf_Shdr& section) override;
  211. void PostProcessRel32() override;
  212. // Specialized Read/Write functions.
  213. std::unique_ptr<ReferenceReader> MakeReadAbs32(offset_t lo, offset_t hi);
  214. std::unique_ptr<ReferenceWriter> MakeWriteAbs32(MutableBufferView image);
  215. std::unique_ptr<ReferenceReader> MakeReadRel32(offset_t lo, offset_t hi);
  216. std::unique_ptr<ReferenceWriter> MakeWriteRel32(MutableBufferView image);
  217. private:
  218. // Sorted file offsets of rel32 locations.
  219. // Using std::deque to reduce peak memory footprint.
  220. std::deque<offset_t> rel32_locations_;
  221. };
  222. using DisassemblerElfX86 = DisassemblerElfIntel<Elf32IntelTraits>;
  223. using DisassemblerElfX64 = DisassemblerElfIntel<Elf64IntelTraits>;
  224. // Disassembler for ELF with ARM architectures.
  225. template <class TRAITS>
  226. class DisassemblerElfArm : public DisassemblerElf<TRAITS> {
  227. public:
  228. using Traits = TRAITS;
  229. DisassemblerElfArm();
  230. DisassemblerElfArm(const DisassemblerElfArm&) = delete;
  231. const DisassemblerElfArm& operator=(const DisassemblerElfArm&) = delete;
  232. ~DisassemblerElfArm() override;
  233. // Determines whether target |offset| is in an executable section.
  234. bool IsTargetOffsetInExecSection(offset_t offset) const;
  235. // Creates an architecture-specific Rel32Finder for ParseExecSection.
  236. virtual std::unique_ptr<typename Traits::Rel32FinderUse> MakeRel32Finder(
  237. const typename Traits::Elf_Shdr& section) = 0;
  238. // DisassemblerElf:
  239. void ParseExecSection(const typename Traits::Elf_Shdr& section) override;
  240. void PostProcessRel32() override;
  241. // Specialized Read/Write functions.
  242. std::unique_ptr<ReferenceReader> MakeReadAbs32(offset_t lo, offset_t hi);
  243. std::unique_ptr<ReferenceWriter> MakeWriteAbs32(MutableBufferView image);
  244. // Specialized Read/Write/Mix functions for different rel32 address types.
  245. template <class ADDR_TRAITS>
  246. std::unique_ptr<ReferenceReader> MakeReadRel32(offset_t lower,
  247. offset_t upper);
  248. template <class ADDR_TRAITS>
  249. std::unique_ptr<ReferenceWriter> MakeWriteRel32(MutableBufferView image);
  250. template <class ADDR_TRAITS>
  251. std::unique_ptr<ReferenceMixer> MakeMixRel32(ConstBufferView old_image,
  252. ConstBufferView new_image);
  253. protected:
  254. // Sorted file offsets of rel32 locations for each rel32 address type.
  255. std::deque<offset_t>
  256. rel32_locations_table_[Traits::ArmReferenceType::kTypeCount];
  257. };
  258. // Disassembler for ELF with AArch32 (AKA ARM32).
  259. class DisassemblerElfAArch32 : public DisassemblerElfArm<ElfAArch32Traits> {
  260. public:
  261. DisassemblerElfAArch32();
  262. DisassemblerElfAArch32(const DisassemblerElfAArch32&) = delete;
  263. const DisassemblerElfAArch32& operator=(const DisassemblerElfAArch32&) =
  264. delete;
  265. ~DisassemblerElfAArch32() override;
  266. // Disassembler:
  267. std::vector<ReferenceGroup> MakeReferenceGroups() const override;
  268. // DisassemblerElfArm:
  269. std::unique_ptr<typename Traits::Rel32FinderUse> MakeRel32Finder(
  270. const typename Traits::Elf_Shdr& section) override;
  271. // Under the naive assumption that an executable section is entirely ARM mode
  272. // or THUMB2 mode, this function implements heuristics to distinguish between
  273. // the two. Returns true if section is THUMB2 mode; otherwise return false.
  274. bool IsExecSectionThumb2(const typename Traits::Elf_Shdr& section) const;
  275. };
  276. // Disassembler for ELF with AArch64 (AKA ARM64).
  277. class DisassemblerElfAArch64 : public DisassemblerElfArm<ElfAArch64Traits> {
  278. public:
  279. DisassemblerElfAArch64();
  280. DisassemblerElfAArch64(const DisassemblerElfAArch64&) = delete;
  281. const DisassemblerElfAArch64& operator=(const DisassemblerElfAArch64&) =
  282. delete;
  283. ~DisassemblerElfAArch64() override;
  284. // Disassembler:
  285. std::vector<ReferenceGroup> MakeReferenceGroups() const override;
  286. // DisassemblerElfArm:
  287. std::unique_ptr<typename Traits::Rel32FinderUse> MakeRel32Finder(
  288. const typename Traits::Elf_Shdr& section) override;
  289. };
  290. } // namespace zucchini
  291. #endif // COMPONENTS_ZUCCHINI_DISASSEMBLER_ELF_H_