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