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