• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include "components/zucchini/disassembler_elf.h"
6 
7 #include <stddef.h>
8 
9 #include <utility>
10 
11 #include "base/logging.h"
12 #include "base/numerics/checked_math.h"
13 #include "base/numerics/safe_conversions.h"
14 #include "components/zucchini/abs32_utils.h"
15 #include "components/zucchini/algorithm.h"
16 #include "components/zucchini/arm_utils.h"
17 #include "components/zucchini/buffer_source.h"
18 
19 namespace zucchini {
20 
21 namespace {
22 
23 constexpr uint64_t kElfImageBase = 0;
24 constexpr size_t kSizeBound = 0x7FFF0000;
25 
26 // Threshold value for heuristics to detect THUMB2 code.
27 constexpr double kAArch32BitCondAlwaysDensityThreshold = 0.4;
28 
29 // Bit fields for JudgeSection() return value.
30 enum SectionJudgement : int {
31   // Bit: Section does not invalidate ELF, but may or may not be useful.
32   SECTION_BIT_SAFE = 1 << 0,
33   // Bit: Section useful for AddressTranslator, to map between offsets and RVAs.
34   SECTION_BIT_USEFUL_FOR_ADDRESS_TRANSLATOR = 1 << 1,
35   // Bit: Section useful for |offset_bound|, to estimate ELF size.
36   SECTION_BIT_USEFUL_FOR_OFFSET_BOUND = 1 << 2,
37   // Bit: Section potentially useful for pointer extraction.
38   SECTION_BIT_MAYBE_USEFUL_FOR_POINTERS = 1 << 3,
39 
40   // The following are verdicts from combining bits, to improve semantics.
41   // Default value: A section is malformed and invalidates ELF.
42   SECTION_IS_MALFORMED = 0,
43   // Section does not invalidate ELF, but is also not used for anything.
44   SECTION_IS_USELESS = SECTION_BIT_SAFE,
45 };
46 
47 // Decides how a section affects ELF parsing, and returns a bit field composed
48 // from SectionJudgement values.
49 template <class TRAITS>
JudgeSection(size_t image_size,const typename TRAITS::Elf_Shdr * section)50 int JudgeSection(size_t image_size, const typename TRAITS::Elf_Shdr* section) {
51   // BufferRegion uses |size_t| this can be 32-bit in some cases. For Elf64
52   // |sh_addr|, |sh_offset| and |sh_size| are 64-bit this can result in
53   // overflows in the subsequent validation steps.
54   if (!base::IsValueInRangeForNumericType<size_t>(section->sh_addr) ||
55       !base::IsValueInRangeForNumericType<size_t>(section->sh_offset) ||
56       !base::IsValueInRangeForNumericType<size_t>(section->sh_size)) {
57     return SECTION_IS_MALFORMED;
58   }
59 
60   // Examine RVA range: Reject if numerical overflow may happen.
61   if (!BufferRegion{static_cast<size_t>(section->sh_addr),
62                     static_cast<size_t>(section->sh_size)}
63            .FitsIn(kSizeBound))
64     return SECTION_IS_MALFORMED;
65 
66   // Examine offset range: If section takes up |image| data then be stricter.
67   size_t offset_bound =
68       (section->sh_type == elf::SHT_NOBITS) ? kSizeBound : image_size;
69   if (!BufferRegion{static_cast<size_t>(section->sh_offset),
70                     static_cast<size_t>(section->sh_size)}
71            .FitsIn(offset_bound))
72     return SECTION_IS_MALFORMED;
73 
74   // Empty sections don't contribute to offset-RVA mapping. For consistency, it
75   // should also not affect |offset_bounds|.
76   if (section->sh_size == 0)
77     return SECTION_IS_USELESS;
78 
79   // Sections with |sh_addr == 0| are ignored because these tend to duplicates
80   // (can cause problems for lookup) and uninteresting. For consistency, it
81   // should also not affect |offset_bounds|.
82   if (section->sh_addr == 0)
83     return SECTION_IS_USELESS;
84 
85   if (section->sh_type == elf::SHT_NOBITS) {
86     // Special case for .tbss sections: These should be ignored because they may
87     // have offset-RVA map that don't match other sections.
88     if (section->sh_flags & elf::SHF_TLS)
89       return SECTION_IS_USELESS;
90 
91     // Section is useful for offset-RVA translation, but does not affect
92     // |offset_bounds| since it can have large virtual size (e.g., .bss).
93     return SECTION_BIT_SAFE | SECTION_BIT_USEFUL_FOR_ADDRESS_TRANSLATOR;
94   }
95 
96   return SECTION_BIT_SAFE | SECTION_BIT_USEFUL_FOR_ADDRESS_TRANSLATOR |
97          SECTION_BIT_USEFUL_FOR_OFFSET_BOUND |
98          SECTION_BIT_MAYBE_USEFUL_FOR_POINTERS;
99 }
100 
101 // Determines whether |section| is a reloc section.
102 template <class TRAITS>
IsRelocSection(const typename TRAITS::Elf_Shdr & section)103 bool IsRelocSection(const typename TRAITS::Elf_Shdr& section) {
104   DCHECK_GT(section.sh_size, 0U);
105   if (section.sh_type == elf::SHT_REL) {
106     // Also validate |section.sh_entsize|, which gets used later.
107     return section.sh_entsize == sizeof(typename TRAITS::Elf_Rel);
108   }
109   if (section.sh_type == elf::SHT_RELA)
110     return section.sh_entsize == sizeof(typename TRAITS::Elf_Rela);
111   return false;
112 }
113 
114 // Determines whether |section| is a section with executable code.
115 template <class TRAITS>
IsExecSection(const typename TRAITS::Elf_Shdr & section)116 bool IsExecSection(const typename TRAITS::Elf_Shdr& section) {
117   DCHECK_GT(section.sh_size, 0U);
118   return section.sh_type == elf::SHT_PROGBITS &&
119          (section.sh_flags & elf::SHF_EXECINSTR) != 0;
120 }
121 
122 }  // namespace
123 
124 /******** Elf32Traits ********/
125 
126 // static
127 constexpr Bitness Elf32Traits::kBitness;
128 constexpr elf::FileClass Elf32Traits::kIdentificationClass;
129 
130 /******** Elf32IntelTraits ********/
131 
132 // static
133 constexpr ExecutableType Elf32IntelTraits::kExeType;
134 const char Elf32IntelTraits::kExeTypeString[] = "ELF x86";
135 constexpr elf::MachineArchitecture Elf32IntelTraits::kMachineValue;
136 constexpr uint32_t Elf32IntelTraits::kRelType;
137 
138 /******** ElfAArch32Traits ********/
139 
140 // static
141 constexpr ExecutableType ElfAArch32Traits::kExeType;
142 const char ElfAArch32Traits::kExeTypeString[] = "ELF ARM";
143 constexpr elf::MachineArchitecture ElfAArch32Traits::kMachineValue;
144 constexpr uint32_t ElfAArch32Traits::kRelType;
145 
146 /******** Elf64Traits ********/
147 
148 // static
149 constexpr Bitness Elf64Traits::kBitness;
150 constexpr elf::FileClass Elf64Traits::kIdentificationClass;
151 
152 /******** Elf64IntelTraits ********/
153 
154 // static
155 constexpr ExecutableType Elf64IntelTraits::kExeType;
156 const char Elf64IntelTraits::kExeTypeString[] = "ELF x64";
157 constexpr elf::MachineArchitecture Elf64IntelTraits::kMachineValue;
158 constexpr uint32_t Elf64IntelTraits::kRelType;
159 
160 /******** ElfAArch64Traits ********/
161 
162 // static
163 constexpr ExecutableType ElfAArch64Traits::kExeType;
164 const char ElfAArch64Traits::kExeTypeString[] = "ELF ARM64";
165 constexpr elf::MachineArchitecture ElfAArch64Traits::kMachineValue;
166 constexpr uint32_t ElfAArch64Traits::kRelType;
167 
168 /******** DisassemblerElf ********/
169 
170 // static.
171 template <class TRAITS>
QuickDetect(ConstBufferView image)172 bool DisassemblerElf<TRAITS>::QuickDetect(ConstBufferView image) {
173   BufferSource source(image);
174 
175   // Do not consume the bytes for the magic value, as they are part of the
176   // header.
177   if (!source.CheckNextBytes({0x7F, 'E', 'L', 'F'}))
178     return false;
179 
180   auto* header = source.GetPointer<typename Traits::Elf_Ehdr>();
181   if (!header)
182     return false;
183 
184   if (header->e_ident[elf::EI_CLASS] != Traits::kIdentificationClass)
185     return false;
186 
187   if (header->e_ident[elf::EI_DATA] != 1)  // Only ELFDATA2LSB is supported.
188     return false;
189 
190   if (header->e_type != elf::ET_EXEC && header->e_type != elf::ET_DYN)
191     return false;
192 
193   if (header->e_version != 1 || header->e_ident[elf::EI_VERSION] != 1)
194     return false;
195 
196   if (header->e_machine != supported_architecture())
197     return false;
198 
199   if (header->e_shentsize != sizeof(typename Traits::Elf_Shdr))
200     return false;
201 
202   return true;
203 }
204 
205 template <class TRAITS>
206 DisassemblerElf<TRAITS>::~DisassemblerElf() = default;
207 
208 template <class TRAITS>
GetExeType() const209 ExecutableType DisassemblerElf<TRAITS>::GetExeType() const {
210   return Traits::kExeType;
211 }
212 
213 template <class TRAITS>
GetExeTypeString() const214 std::string DisassemblerElf<TRAITS>::GetExeTypeString() const {
215   return Traits::kExeTypeString;
216 }
217 
218 // |num_equivalence_iterations_| = 2 for reloc -> abs32.
219 template <class TRAITS>
DisassemblerElf()220 DisassemblerElf<TRAITS>::DisassemblerElf() : Disassembler(2) {}
221 
222 template <class TRAITS>
Parse(ConstBufferView image)223 bool DisassemblerElf<TRAITS>::Parse(ConstBufferView image) {
224   image_ = image;
225   if (!ParseHeader())
226     return false;
227   ParseSections();
228   return true;
229 }
230 
231 template <class TRAITS>
MakeReadRelocs(offset_t lo,offset_t hi)232 std::unique_ptr<ReferenceReader> DisassemblerElf<TRAITS>::MakeReadRelocs(
233     offset_t lo,
234     offset_t hi) {
235   DCHECK_LE(lo, hi);
236   DCHECK_LE(hi, image_.size());
237 
238   if (reloc_section_dims_.empty())
239     return std::make_unique<EmptyReferenceReader>();
240 
241   return std::make_unique<RelocReaderElf>(
242       image_, Traits::kBitness, reloc_section_dims_,
243       supported_relocation_type(), lo, hi, translator_);
244 }
245 
246 template <class TRAITS>
MakeWriteRelocs(MutableBufferView image)247 std::unique_ptr<ReferenceWriter> DisassemblerElf<TRAITS>::MakeWriteRelocs(
248     MutableBufferView image) {
249   return std::make_unique<RelocWriterElf>(image, Traits::kBitness, translator_);
250 }
251 
252 template <class TRAITS>
ParseHeader()253 bool DisassemblerElf<TRAITS>::ParseHeader() {
254   BufferSource source(image_);
255   // Ensure any offsets will fit within the |image_|'s bounds.
256   if (!base::IsValueInRangeForNumericType<offset_t>(image_.size()))
257     return false;
258 
259   // Ensures |header_| is valid later on.
260   if (!QuickDetect(image_))
261     return false;
262 
263   header_ = source.GetPointer<typename Traits::Elf_Ehdr>();
264 
265   sections_count_ = header_->e_shnum;
266   source = std::move(BufferSource(image_).Skip(header_->e_shoff));
267   sections_ = source.GetArray<typename Traits::Elf_Shdr>(sections_count_);
268   if (!sections_)
269     return false;
270   offset_t section_table_end =
271       base::checked_cast<offset_t>(source.begin() - image_.begin());
272 
273   segments_count_ = header_->e_phnum;
274   source = std::move(BufferSource(image_).Skip(header_->e_phoff));
275   segments_ = source.GetArray<typename Traits::Elf_Phdr>(segments_count_);
276   if (!segments_)
277     return false;
278   offset_t segment_table_end =
279       base::checked_cast<offset_t>(source.begin() - image_.begin());
280 
281   // Check string section -- even though we've stopped using them.
282   elf::Elf32_Half string_section_id = header_->e_shstrndx;
283   if (string_section_id >= sections_count_)
284     return false;
285   size_t section_names_size = sections_[string_section_id].sh_size;
286   if (section_names_size > 0) {
287     // If nonempty, then last byte of string section must be null.
288     const char* section_names = nullptr;
289     source = std::move(
290         BufferSource(image_).Skip(sections_[string_section_id].sh_offset));
291     section_names = source.GetArray<char>(section_names_size);
292     if (!section_names || section_names[section_names_size - 1] != '\0')
293       return false;
294   }
295 
296   // Establish bound on encountered offsets.
297   offset_t offset_bound = std::max(section_table_end, segment_table_end);
298 
299   // Visits |segments_| to get estimate on |offset_bound|.
300   for (const typename Traits::Elf_Phdr* segment = segments_;
301        segment != segments_ + segments_count_; ++segment) {
302     // |image_.covers()| is a sufficient check except when size_t is 32 bit and
303     // parsing ELF64. In such cases a value-in-range check is needed on the
304     // segment. This fixes crbug/1035603.
305     offset_t segment_end;
306     base::CheckedNumeric<offset_t> checked_segment_end = segment->p_offset;
307     checked_segment_end += segment->p_filesz;
308     if (!checked_segment_end.AssignIfValid(&segment_end) ||
309         !image_.covers({static_cast<size_t>(segment->p_offset),
310                         static_cast<size_t>(segment->p_filesz)})) {
311       return false;
312     }
313     offset_bound = std::max(offset_bound, segment_end);
314   }
315 
316   // Visit and validate each section; add address translation data to |units|.
317   std::vector<AddressTranslator::Unit> units;
318   units.reserve(sections_count_);
319   section_judgements_.reserve(sections_count_);
320 
321   for (int i = 0; i < sections_count_; ++i) {
322     const typename Traits::Elf_Shdr* section = &sections_[i];
323     int judgement = JudgeSection<Traits>(image_.size(), section);
324     section_judgements_.push_back(judgement);
325     if ((judgement & SECTION_BIT_SAFE) == 0)
326       return false;
327 
328     uint32_t sh_size = base::checked_cast<uint32_t>(section->sh_size);
329     offset_t sh_offset = base::checked_cast<offset_t>(section->sh_offset);
330     rva_t sh_addr = base::checked_cast<rva_t>(section->sh_addr);
331     if ((judgement & SECTION_BIT_USEFUL_FOR_ADDRESS_TRANSLATOR) != 0) {
332       // Store mappings between RVA and offset.
333       units.push_back({sh_offset, sh_size, sh_addr, sh_size});
334     }
335     if ((judgement & SECTION_BIT_USEFUL_FOR_OFFSET_BOUND) != 0) {
336       offset_t section_end = base::checked_cast<offset_t>(sh_offset + sh_size);
337       offset_bound = std::max(offset_bound, section_end);
338     }
339   }
340 
341   // Initialize |translator_| for offset-RVA translations. Any inconsistency
342   // (e.g., 2 offsets correspond to the same RVA) would invalidate the ELF file.
343   if (translator_.Initialize(std::move(units)) != AddressTranslator::kSuccess)
344     return false;
345 
346   DCHECK_LE(offset_bound, image_.size());
347   image_.shrink(offset_bound);
348   return true;
349 }
350 
351 template <class TRAITS>
ExtractInterestingSectionHeaders()352 void DisassemblerElf<TRAITS>::ExtractInterestingSectionHeaders() {
353   DCHECK(reloc_section_dims_.empty());
354   DCHECK(exec_headers_.empty());
355   for (elf::Elf32_Half i = 0; i < sections_count_; ++i) {
356     const typename Traits::Elf_Shdr* section = sections_ + i;
357     if ((section_judgements_[i] & SECTION_BIT_MAYBE_USEFUL_FOR_POINTERS) != 0) {
358       if (IsRelocSection<Traits>(*section))
359         reloc_section_dims_.emplace_back(*section);
360       else if (IsExecSection<Traits>(*section))
361         exec_headers_.push_back(section);
362     }
363   }
364   auto comp = [](const typename Traits::Elf_Shdr* a,
365                  const typename Traits::Elf_Shdr* b) {
366     return a->sh_offset < b->sh_offset;
367   };
368   std::sort(reloc_section_dims_.begin(), reloc_section_dims_.end());
369   std::sort(exec_headers_.begin(), exec_headers_.end(), comp);
370 }
371 
372 template <class TRAITS>
GetAbs32FromRelocSections()373 void DisassemblerElf<TRAITS>::GetAbs32FromRelocSections() {
374   constexpr int kAbs32Width = Traits::kVAWidth;
375   DCHECK(abs32_locations_.empty());
376 
377   // Read reloc targets to get preliminary abs32 locations.
378   std::unique_ptr<ReferenceReader> relocs = MakeReadRelocs(0, offset_t(size()));
379   for (auto ref = relocs->GetNext(); ref.has_value(); ref = relocs->GetNext())
380     abs32_locations_.push_back(ref->target);
381 
382   std::sort(abs32_locations_.begin(), abs32_locations_.end());
383 
384   // Abs32 references must have targets translatable to offsets. Remove those
385   // that are unable to do so.
386   size_t num_untranslatable =
387       RemoveUntranslatableAbs32(image_, {Traits::kBitness, kElfImageBase},
388                                 translator_, &abs32_locations_);
389   LOG_IF(WARNING, num_untranslatable) << "Removed " << num_untranslatable
390                                       << " untranslatable abs32 references.";
391 
392   // Abs32 reference bodies must not overlap. If found, simply remove them.
393   size_t num_overlapping =
394       RemoveOverlappingAbs32Locations(kAbs32Width, &abs32_locations_);
395   LOG_IF(WARNING, num_overlapping)
396       << "Removed " << num_overlapping
397       << " abs32 references with overlapping bodies.";
398 
399   abs32_locations_.shrink_to_fit();
400 }
401 
402 template <class TRAITS>
GetRel32FromCodeSections()403 void DisassemblerElf<TRAITS>::GetRel32FromCodeSections() {
404   for (const typename Traits::Elf_Shdr* section : exec_headers_)
405     ParseExecSection(*section);
406   PostProcessRel32();
407 }
408 
409 template <class TRAITS>
ParseSections()410 void DisassemblerElf<TRAITS>::ParseSections() {
411   ExtractInterestingSectionHeaders();
412   GetAbs32FromRelocSections();
413   GetRel32FromCodeSections();
414 }
415 
416 /******** DisassemblerElfIntel ********/
417 
418 template <class TRAITS>
419 DisassemblerElfIntel<TRAITS>::DisassemblerElfIntel() = default;
420 
421 template <class TRAITS>
422 DisassemblerElfIntel<TRAITS>::~DisassemblerElfIntel() = default;
423 
424 template <class TRAITS>
MakeReferenceGroups() const425 std::vector<ReferenceGroup> DisassemblerElfIntel<TRAITS>::MakeReferenceGroups()
426     const {
427   return {
428       {ReferenceTypeTraits{sizeof(TRAITS::Elf_Rel::r_offset), TypeTag(kReloc),
429                            PoolTag(kReloc)},
430        &DisassemblerElfIntel<TRAITS>::MakeReadRelocs,
431        &DisassemblerElfIntel<TRAITS>::MakeWriteRelocs},
432       {ReferenceTypeTraits{Traits::kVAWidth, TypeTag(kAbs32), PoolTag(kAbs32)},
433        &DisassemblerElfIntel<TRAITS>::MakeReadAbs32,
434        &DisassemblerElfIntel<TRAITS>::MakeWriteAbs32},
435       // N.B.: Rel32 |width| is 4 bytes, even for x64.
436       {ReferenceTypeTraits{4, TypeTag(kRel32), PoolTag(kRel32)},
437        &DisassemblerElfIntel<TRAITS>::MakeReadRel32,
438        &DisassemblerElfIntel<TRAITS>::MakeWriteRel32}};
439 }
440 
441 template <class TRAITS>
ParseExecSection(const typename TRAITS::Elf_Shdr & section)442 void DisassemblerElfIntel<TRAITS>::ParseExecSection(
443     const typename TRAITS::Elf_Shdr& section) {
444   constexpr int kAbs32Width = Traits::kVAWidth;
445 
446   // |this->| is needed to access protected members of templated base class. To
447   // reduce noise, use local references for these.
448   ConstBufferView& image_ = this->image_;
449   const AddressTranslator& translator_ = this->translator_;
450   auto& abs32_locations_ = this->abs32_locations_;
451 
452   // Range of values was ensured in ParseHeader().
453   rva_t start_rva = base::checked_cast<rva_t>(section.sh_addr);
454   rva_t end_rva = base::checked_cast<rva_t>(start_rva + section.sh_size);
455 
456   AddressTranslator::RvaToOffsetCache target_rva_checker(translator_);
457 
458   ConstBufferView region(image_.begin() + section.sh_offset, section.sh_size);
459   Abs32GapFinder gap_finder(image_, region, abs32_locations_, kAbs32Width);
460   typename TRAITS::Rel32FinderUse rel_finder(image_, translator_);
461   // Iterate over gaps between abs32 references, to avoid collision.
462   while (gap_finder.FindNext()) {
463     rel_finder.SetRegion(gap_finder.GetGap());
464     while (rel_finder.FindNext()) {
465       auto rel32 = rel_finder.GetRel32();
466       if (target_rva_checker.IsValid(rel32.target_rva) &&
467           (rel32.can_point_outside_section ||
468            (start_rva <= rel32.target_rva && rel32.target_rva < end_rva))) {
469         rel_finder.Accept();
470         rel32_locations_.push_back(rel32.location);
471       }
472     }
473   }
474 }
475 
476 template <class TRAITS>
PostProcessRel32()477 void DisassemblerElfIntel<TRAITS>::PostProcessRel32() {
478   rel32_locations_.shrink_to_fit();
479   std::sort(rel32_locations_.begin(), rel32_locations_.end());
480 }
481 
482 template <class TRAITS>
MakeReadAbs32(offset_t lo,offset_t hi)483 std::unique_ptr<ReferenceReader> DisassemblerElfIntel<TRAITS>::MakeReadAbs32(
484     offset_t lo,
485     offset_t hi) {
486   // TODO(huangs): Don't use Abs32RvaExtractorWin32 here; use new class that
487   // caters to different ELF architectures.
488   Abs32RvaExtractorWin32 abs_rva_extractor(
489       this->image_, AbsoluteAddress(TRAITS::kBitness, kElfImageBase),
490       this->abs32_locations_, lo, hi);
491   return std::make_unique<Abs32ReaderWin32>(std::move(abs_rva_extractor),
492                                             this->translator_);
493 }
494 
495 template <class TRAITS>
MakeWriteAbs32(MutableBufferView image)496 std::unique_ptr<ReferenceWriter> DisassemblerElfIntel<TRAITS>::MakeWriteAbs32(
497     MutableBufferView image) {
498   return std::make_unique<Abs32WriterWin32>(
499       image, AbsoluteAddress(TRAITS::kBitness, kElfImageBase),
500       this->translator_);
501 }
502 
503 template <class TRAITS>
MakeReadRel32(offset_t lo,offset_t hi)504 std::unique_ptr<ReferenceReader> DisassemblerElfIntel<TRAITS>::MakeReadRel32(
505     offset_t lo,
506     offset_t hi) {
507   return std::make_unique<Rel32ReaderX86>(this->image_, lo, hi,
508                                           &rel32_locations_, this->translator_);
509 }
510 
511 template <class TRAITS>
MakeWriteRel32(MutableBufferView image)512 std::unique_ptr<ReferenceWriter> DisassemblerElfIntel<TRAITS>::MakeWriteRel32(
513     MutableBufferView image) {
514   return std::make_unique<Rel32WriterX86>(image, this->translator_);
515 }
516 
517 // Explicit instantiation for supported classes.
518 template class DisassemblerElfIntel<Elf32IntelTraits>;
519 template class DisassemblerElfIntel<Elf64IntelTraits>;
520 template bool DisassemblerElf<Elf32IntelTraits>::QuickDetect(
521     ConstBufferView image);
522 template bool DisassemblerElf<Elf64IntelTraits>::QuickDetect(
523     ConstBufferView image);
524 
525 /******** DisassemblerElfArm ********/
526 
527 template <class Traits>
528 DisassemblerElfArm<Traits>::DisassemblerElfArm() = default;
529 
530 template <class Traits>
531 DisassemblerElfArm<Traits>::~DisassemblerElfArm() = default;
532 
533 template <class Traits>
IsTargetOffsetInExecSection(offset_t offset) const534 bool DisassemblerElfArm<Traits>::IsTargetOffsetInExecSection(
535     offset_t offset) const {
536   // Executable sections can appear in large numbers in .o files and in
537   // pathological cases. Since this function may be called for each reference
538   // candidate, linear search may be too slow (so use binary search).
539   return IsTargetOffsetInElfSectionList(this->exec_headers_, offset);
540 }
541 
542 template <class Traits>
ParseExecSection(const typename Traits::Elf_Shdr & section)543 void DisassemblerElfArm<Traits>::ParseExecSection(
544     const typename Traits::Elf_Shdr& section) {
545   ConstBufferView& image_ = this->image_;
546   const AddressTranslator& translator_ = this->translator_;
547   auto& abs32_locations_ = this->abs32_locations_;
548 
549   ConstBufferView region(image_.begin() + section.sh_offset, section.sh_size);
550   Abs32GapFinder gap_finder(image_, region, abs32_locations_, Traits::kVAWidth);
551   std::unique_ptr<typename Traits::Rel32FinderUse> rel_finder =
552       MakeRel32Finder(section);
553   AddressTranslator::RvaToOffsetCache rva_to_offset(translator_);
554   while (gap_finder.FindNext()) {
555     rel_finder->SetRegion(gap_finder.GetGap());
556     while (rel_finder->FindNext()) {
557       auto rel32 = rel_finder->GetRel32();
558       offset_t target_offset = rva_to_offset.Convert(rel32.target_rva);
559       if (target_offset != kInvalidOffset) {
560         // For robustness, reject illegal offsets, which can arise from, e.g.,
561         // misidentify ARM vs. THUMB2 mode, or even misidentifying data as code!
562         if (IsTargetOffsetInExecSection(target_offset)) {
563           rel_finder->Accept();
564           rel32_locations_table_[rel32.type].push_back(rel32.location);
565         }
566       }
567     }
568   }
569 }
570 
571 template <class Traits>
PostProcessRel32()572 void DisassemblerElfArm<Traits>::PostProcessRel32() {
573   for (int type = 0; type < AArch32Rel32Translator::NUM_ADDR_TYPE; ++type) {
574     std::sort(rel32_locations_table_[type].begin(),
575               rel32_locations_table_[type].end());
576     rel32_locations_table_[type].shrink_to_fit();
577   }
578 }
579 
580 template <class Traits>
MakeReadAbs32(offset_t lo,offset_t hi)581 std::unique_ptr<ReferenceReader> DisassemblerElfArm<Traits>::MakeReadAbs32(
582     offset_t lo,
583     offset_t hi) {
584   // TODO(huangs): Reconcile the use of Win32-specific classes in ARM code!
585   Abs32RvaExtractorWin32 abs_rva_extractor(this->image_,
586                                            AbsoluteAddress(Traits::kBitness, 0),
587                                            this->abs32_locations_, lo, hi);
588   return std::make_unique<Abs32ReaderWin32>(std::move(abs_rva_extractor),
589                                             this->translator_);
590 }
591 
592 template <class Traits>
MakeWriteAbs32(MutableBufferView image)593 std::unique_ptr<ReferenceWriter> DisassemblerElfArm<Traits>::MakeWriteAbs32(
594     MutableBufferView image) {
595   return std::make_unique<Abs32WriterWin32>(
596       image, AbsoluteAddress(Traits::kBitness, 0), this->translator_);
597 }
598 
599 template <class TRAITS>
600 template <class ADDR_TRAITS>
MakeReadRel32(offset_t lower,offset_t upper)601 std::unique_ptr<ReferenceReader> DisassemblerElfArm<TRAITS>::MakeReadRel32(
602     offset_t lower,
603     offset_t upper) {
604   return std::make_unique<Rel32ReaderArm<ADDR_TRAITS>>(
605       this->translator_, this->image_,
606       this->rel32_locations_table_[ADDR_TRAITS::addr_type], lower, upper);
607 }
608 
609 template <class TRAITS>
610 template <class ADDR_TRAITS>
MakeWriteRel32(MutableBufferView image)611 std::unique_ptr<ReferenceWriter> DisassemblerElfArm<TRAITS>::MakeWriteRel32(
612     MutableBufferView image) {
613   return std::make_unique<Rel32WriterArm<ADDR_TRAITS>>(this->translator_,
614                                                        image);
615 }
616 
617 /******** DisassemblerElfAArch32 ********/
618 
619 DisassemblerElfAArch32::DisassemblerElfAArch32() = default;
620 DisassemblerElfAArch32::~DisassemblerElfAArch32() = default;
621 
MakeReferenceGroups() const622 std::vector<ReferenceGroup> DisassemblerElfAArch32::MakeReferenceGroups()
623     const {
624   return {
625       {ReferenceTypeTraits{sizeof(Traits::Elf_Rel::r_offset),
626                            TypeTag(AArch32ReferenceType::kReloc),
627                            PoolTag(ArmReferencePool::kPoolReloc)},
628        &DisassemblerElfAArch32::MakeReadRelocs,
629        &DisassemblerElfAArch32::MakeWriteRelocs},
630       {ReferenceTypeTraits{Traits::kVAWidth,
631                            TypeTag(AArch32ReferenceType::kAbs32),
632                            PoolTag(ArmReferencePool::kPoolAbs32)},
633        &DisassemblerElfAArch32::MakeReadAbs32,
634        &DisassemblerElfAArch32::MakeWriteAbs32},
635       {ReferenceTypeTraits{4, TypeTag(AArch32ReferenceType::kRel32_A24),
636                            PoolTag(ArmReferencePool::kPoolRel32)},
637        &DisassemblerElfAArch32::MakeReadRel32<
638            AArch32Rel32Translator::AddrTraits_A24>,
639        &DisassemblerElfAArch32::MakeWriteRel32<
640            AArch32Rel32Translator::AddrTraits_A24>},
641       {ReferenceTypeTraits{2, TypeTag(AArch32ReferenceType::kRel32_T8),
642                            PoolTag(ArmReferencePool::kPoolRel32)},
643        &DisassemblerElfAArch32::MakeReadRel32<
644            AArch32Rel32Translator::AddrTraits_T8>,
645        &DisassemblerElfAArch32::MakeWriteRel32<
646            AArch32Rel32Translator::AddrTraits_T8>},
647       {ReferenceTypeTraits{2, TypeTag(AArch32ReferenceType::kRel32_T11),
648                            PoolTag(ArmReferencePool::kPoolRel32)},
649        &DisassemblerElfAArch32::MakeReadRel32<
650            AArch32Rel32Translator::AddrTraits_T11>,
651        &DisassemblerElfAArch32::MakeWriteRel32<
652            AArch32Rel32Translator::AddrTraits_T11>},
653       {ReferenceTypeTraits{4, TypeTag(AArch32ReferenceType::kRel32_T20),
654                            PoolTag(ArmReferencePool::kPoolRel32)},
655        &DisassemblerElfAArch32::MakeReadRel32<
656            AArch32Rel32Translator::AddrTraits_T20>,
657        &DisassemblerElfAArch32::MakeWriteRel32<
658            AArch32Rel32Translator::AddrTraits_T20>},
659       {ReferenceTypeTraits{4, TypeTag(AArch32ReferenceType::kRel32_T24),
660                            PoolTag(ArmReferencePool::kPoolRel32)},
661        &DisassemblerElfAArch32::MakeReadRel32<
662            AArch32Rel32Translator::AddrTraits_T24>,
663        &DisassemblerElfAArch32::MakeWriteRel32<
664            AArch32Rel32Translator::AddrTraits_T24>},
665   };
666 }
667 
668 std::unique_ptr<DisassemblerElfAArch32::Traits::Rel32FinderUse>
MakeRel32Finder(const typename Traits::Elf_Shdr & section)669 DisassemblerElfAArch32::MakeRel32Finder(
670     const typename Traits::Elf_Shdr& section) {
671   return std::make_unique<Rel32FinderAArch32>(image_, translator_,
672                                               IsExecSectionThumb2(section));
673 }
674 
IsExecSectionThumb2(const typename Traits::Elf_Shdr & section) const675 bool DisassemblerElfAArch32::IsExecSectionThumb2(
676     const typename Traits::Elf_Shdr& section) const {
677   // ARM mode requires 4-byte alignment.
678   if (section.sh_addr % 4 != 0 || section.sh_size % 4 != 0)
679     return true;
680   const uint8_t* first = image_.begin() + section.sh_offset;
681   const uint8_t* end = first + section.sh_size;
682   // Each instruction in 32-bit ARM (little-endian) looks like
683   //   ?? ?? ?? X?,
684   // where X specifies conditional execution. X = 0xE represents AL = "ALways
685   // execute", and tends to appear very often. We use this as our main indicator
686   // to discern 32-bit ARM mode from THUMB2 mode.
687   size_t num = 0;
688   size_t den = 0;
689   for (const uint8_t* cur = first; cur < end; cur += 4) {
690     // |cur[3]| is within bounds because |end - cur| is a multiple of 4.
691     uint8_t maybe_cond = cur[3] & 0xF0;
692     if (maybe_cond == 0xE0)
693       ++num;
694     ++den;
695   }
696 
697   if (den > 0) {
698     LOG(INFO) << "Section scan: " << num << " / " << den << " => "
699               << base::StringPrintf("%.2f", num * 100.0 / den) << "%";
700   }
701   return num < den * kAArch32BitCondAlwaysDensityThreshold;
702 }
703 
704 /******** DisassemblerElfAArch64 ********/
705 
706 DisassemblerElfAArch64::DisassemblerElfAArch64() = default;
707 
708 DisassemblerElfAArch64::~DisassemblerElfAArch64() = default;
709 
MakeReferenceGroups() const710 std::vector<ReferenceGroup> DisassemblerElfAArch64::MakeReferenceGroups()
711     const {
712   return {
713       {ReferenceTypeTraits{sizeof(Traits::Elf_Rel::r_offset),
714                            TypeTag(AArch64ReferenceType::kReloc),
715                            PoolTag(ArmReferencePool::kPoolReloc)},
716        &DisassemblerElfAArch64::MakeReadRelocs,
717        &DisassemblerElfAArch64::MakeWriteRelocs},
718       {ReferenceTypeTraits{Traits::kVAWidth,
719                            TypeTag(AArch64ReferenceType::kAbs32),
720                            PoolTag(ArmReferencePool::kPoolAbs32)},
721        &DisassemblerElfAArch64::MakeReadAbs32,
722        &DisassemblerElfAArch64::MakeWriteAbs32},
723       {ReferenceTypeTraits{4, TypeTag(AArch64ReferenceType::kRel32_Immd14),
724                            PoolTag(ArmReferencePool::kPoolRel32)},
725        &DisassemblerElfAArch64::MakeReadRel32<
726            AArch64Rel32Translator::AddrTraits_Immd14>,
727        &DisassemblerElfAArch64::MakeWriteRel32<
728            AArch64Rel32Translator::AddrTraits_Immd14>},
729       {ReferenceTypeTraits{4, TypeTag(AArch64ReferenceType::kRel32_Immd19),
730                            PoolTag(ArmReferencePool::kPoolRel32)},
731        &DisassemblerElfAArch64::MakeReadRel32<
732            AArch64Rel32Translator::AddrTraits_Immd19>,
733        &DisassemblerElfAArch64::MakeWriteRel32<
734            AArch64Rel32Translator::AddrTraits_Immd19>},
735       {ReferenceTypeTraits{4, TypeTag(AArch64ReferenceType::kRel32_Immd26),
736                            PoolTag(ArmReferencePool::kPoolRel32)},
737        &DisassemblerElfAArch64::MakeReadRel32<
738            AArch64Rel32Translator::AddrTraits_Immd26>,
739        &DisassemblerElfAArch64::MakeWriteRel32<
740            AArch64Rel32Translator::AddrTraits_Immd26>},
741   };
742 }
743 
744 std::unique_ptr<DisassemblerElfAArch64::Traits::Rel32FinderUse>
MakeRel32Finder(const typename Traits::Elf_Shdr & section)745 DisassemblerElfAArch64::MakeRel32Finder(
746     const typename Traits::Elf_Shdr& section) {
747   return std::make_unique<Rel32FinderAArch64>(image_, translator_);
748 }
749 
750 // Explicit instantiation for supported classes.
751 template class DisassemblerElfArm<ElfAArch32Traits>;
752 template class DisassemblerElfArm<ElfAArch64Traits>;
753 template bool DisassemblerElf<ElfAArch32Traits>::QuickDetect(
754     ConstBufferView image);
755 template bool DisassemblerElf<ElfAArch64Traits>::QuickDetect(
756     ConstBufferView image);
757 
758 }  // namespace zucchini
759