[M108 Migration][HBBTV] Implement ewk_context_register_jsplugin_mime_types API
[platform/framework/web/chromium-efl.git] / courgette / disassembler_elf_32.cc
1 // Copyright 2013 The Chromium Authors
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 "courgette/disassembler_elf_32.h"
6
7 #include <algorithm>
8 #include <iterator>
9
10 #include "base/bind.h"
11 #include "base/logging.h"
12 #include "courgette/assembly_program.h"
13 #include "courgette/courgette.h"
14
15 namespace courgette {
16
17 namespace {
18
19 // Sorts |section_headers| by file offset and stores the resulting permutation
20 // of section ids in |order|.
21 std::vector<Elf32_Half> GetSectionHeaderFileOffsetOrder(
22     const std::vector<Elf32_Shdr>& section_headers) {
23   size_t size = section_headers.size();
24   std::vector<Elf32_Half> order(size);
25   for (size_t i = 0; i < size; ++i)
26     order[i] = static_cast<Elf32_Half>(i);
27
28   auto comp = [&](int idx1, int idx2) {
29     return section_headers[idx1].sh_offset < section_headers[idx2].sh_offset;
30   };
31   std::stable_sort(order.begin(), order.end(), comp);
32   return order;
33 }
34
35 }  // namespace
36
37 DisassemblerElf32::Elf32RvaVisitor_Rel32::Elf32RvaVisitor_Rel32(
38     const std::vector<std::unique_ptr<TypedRVA>>& rva_locations)
39     : VectorRvaVisitor<std::unique_ptr<TypedRVA>>(rva_locations) {
40 }
41
42 RVA DisassemblerElf32::Elf32RvaVisitor_Rel32::Get() const {
43   return (*it_)->rva() + (*it_)->relative_target();
44 }
45
46 DisassemblerElf32::DisassemblerElf32(const uint8_t* start, size_t length)
47     : Disassembler(start, length),
48       header_(nullptr),
49       section_header_table_size_(0),
50       program_header_table_(nullptr),
51       program_header_table_size_(0),
52       default_string_section_(nullptr) {}
53
54 RVA DisassemblerElf32::FileOffsetToRVA(FileOffset offset) const {
55   // File offsets can be 64-bit values, but we are dealing with 32-bit
56   // executables and so only need to support 32-bit file sizes.
57   uint32_t offset32 = static_cast<uint32_t>(offset);
58
59   // Visit section headers ordered by file offset.
60   for (Elf32_Half section_id : section_header_file_offset_order_) {
61     const Elf32_Shdr* section_header = SectionHeader(section_id);
62     // These can appear to have a size in the file, but don't.
63     if (section_header->sh_type == SHT_NOBITS)
64       continue;
65
66     Elf32_Off section_begin = section_header->sh_offset;
67     Elf32_Off section_end = section_begin + section_header->sh_size;
68
69     if (offset32 >= section_begin && offset32 < section_end) {
70       return section_header->sh_addr + (offset32 - section_begin);
71     }
72   }
73
74   return 0;
75 }
76
77 FileOffset DisassemblerElf32::RVAToFileOffset(RVA rva) const {
78   for (Elf32_Half section_id = 0; section_id < SectionHeaderCount();
79        ++section_id) {
80     const Elf32_Shdr* section_header = SectionHeader(section_id);
81     // These can appear to have a size in the file, but don't.
82     if (section_header->sh_type == SHT_NOBITS)
83       continue;
84     Elf32_Addr begin = section_header->sh_addr;
85     Elf32_Addr end = begin + section_header->sh_size;
86
87     if (rva >= begin && rva < end)
88       return section_header->sh_offset + (rva - begin);
89   }
90   return kNoFileOffset;
91 }
92
93 RVA DisassemblerElf32::PointerToTargetRVA(const uint8_t* p) const {
94   // TODO(huangs): Add check (e.g., IsValidTargetRVA(), but more efficient).
95   return Read32LittleEndian(p);
96 }
97
98 bool DisassemblerElf32::ParseHeader() {
99   if (length() < sizeof(Elf32_Ehdr))
100     return Bad("Too small");
101
102   header_ = reinterpret_cast<const Elf32_Ehdr*>(start());
103
104   // Perform DisassemblerElf32::QuickDetect() checks (with error messages).
105
106   // Have magic for ELF header?
107   if (header_->e_ident[EI_MAG0] != 0x7F || header_->e_ident[EI_MAG1] != 'E' ||
108       header_->e_ident[EI_MAG2] != 'L' || header_->e_ident[EI_MAG3] != 'F') {
109     return Bad("No Magic Number");
110   }
111
112   if (header_->e_ident[EI_CLASS] != ELFCLASS32 ||
113       header_->e_ident[EI_DATA] != ELFDATA2LSB ||
114       header_->e_machine != ElfEM()) {
115     return Bad("Not a supported architecture");
116   }
117
118   if (header_->e_type != ET_EXEC && header_->e_type != ET_DYN)
119     return Bad("Not an executable file or shared library");
120
121   if (header_->e_version != 1 || header_->e_ident[EI_VERSION] != 1)
122     return Bad("Unknown file version");
123
124   if (header_->e_shentsize != sizeof(Elf32_Shdr))
125     return Bad("Unexpected section header size");
126
127   // Perform more complex checks, while extracting data.
128
129   if (header_->e_shoff < sizeof(Elf32_Ehdr) ||
130       !IsArrayInBounds(header_->e_shoff, header_->e_shnum,
131                        sizeof(Elf32_Shdr))) {
132     return Bad("Out of bounds section header table");
133   }
134
135   // Extract |section_header_table_|, ordered by section id.
136   const Elf32_Shdr* section_header_table_raw =
137       reinterpret_cast<const Elf32_Shdr*>(
138           FileOffsetToPointer(header_->e_shoff));
139   section_header_table_size_ = header_->e_shnum;
140   section_header_table_.assign(section_header_table_raw,
141       section_header_table_raw + section_header_table_size_);
142   if (!CheckSectionRanges())
143     return Bad("Out of bound section");
144   section_header_file_offset_order_ =
145       GetSectionHeaderFileOffsetOrder(section_header_table_);
146   if (header_->e_phoff < sizeof(Elf32_Ehdr) ||
147       !IsArrayInBounds(header_->e_phoff, header_->e_phnum,
148                        sizeof(Elf32_Phdr))) {
149     return Bad("Out of bounds program header table");
150   }
151
152   // Extract |program_header_table_|.
153   program_header_table_size_ = header_->e_phnum;
154   program_header_table_ = reinterpret_cast<const Elf32_Phdr*>(
155       FileOffsetToPointer(header_->e_phoff));
156   if (!CheckProgramSegmentRanges())
157     return Bad("Out of bound segment");
158
159   // Extract |default_string_section_|.
160   Elf32_Half string_section_id = header_->e_shstrndx;
161   if (string_section_id == SHN_UNDEF)
162     return Bad("Missing string section");
163   if (string_section_id >= header_->e_shnum)
164     return Bad("Out of bounds string section index");
165   if (SectionHeader(string_section_id)->sh_type != SHT_STRTAB)
166     return Bad("Invalid string section");
167   default_string_section_size_ = SectionHeader(string_section_id)->sh_size;
168   default_string_section_ =
169       reinterpret_cast<const char*>(SectionBody(string_section_id));
170   // String section may be empty. If nonempty, then last byte must be null.
171   if (default_string_section_size_ > 0) {
172     if (default_string_section_[default_string_section_size_ - 1] != '\0')
173       return Bad("String section does not terminate");
174   }
175
176   UpdateLength();
177
178   return Good();
179 }
180
181 CheckBool DisassemblerElf32::IsValidTargetRVA(RVA rva) const {
182   if (rva == kUnassignedRVA)
183     return false;
184
185   // |rva| is valid if it's contained in any program segment.
186   for (Elf32_Half segment_id = 0; segment_id < ProgramSegmentHeaderCount();
187        ++segment_id) {
188     const Elf32_Phdr* segment_header = ProgramSegmentHeader(segment_id);
189
190     if (segment_header->p_type != PT_LOAD)
191       continue;
192
193     Elf32_Addr begin = segment_header->p_vaddr;
194     Elf32_Addr end = segment_header->p_vaddr + segment_header->p_memsz;
195
196     if (rva >= begin && rva < end)
197       return true;
198   }
199
200   return false;
201 }
202
203 // static
204 bool DisassemblerElf32::QuickDetect(const uint8_t* start,
205                                     size_t length,
206                                     e_machine_values elf_em) {
207   if (length < sizeof(Elf32_Ehdr))
208     return false;
209
210   const Elf32_Ehdr* header = reinterpret_cast<const Elf32_Ehdr*>(start);
211
212   // Have magic for ELF header?
213   if (header->e_ident[EI_MAG0] != 0x7F || header->e_ident[EI_MAG1] != 'E' ||
214       header->e_ident[EI_MAG2] != 'L' || header->e_ident[EI_MAG3] != 'F') {
215     return false;
216   }
217   if (header->e_ident[EI_CLASS] != ELFCLASS32 ||
218       header->e_ident[EI_DATA] != ELFDATA2LSB || header->e_machine != elf_em) {
219     return false;
220   }
221   if (header->e_type != ET_EXEC && header->e_type != ET_DYN)
222     return false;
223   if (header->e_version != 1 || header->e_ident[EI_VERSION] != 1)
224     return false;
225   if (header->e_shentsize != sizeof(Elf32_Shdr))
226     return false;
227
228   return true;
229 }
230
231 bool DisassemblerElf32::CheckSectionRanges() {
232   for (Elf32_Half section_id = 0; section_id < SectionHeaderCount();
233        ++section_id) {
234     const Elf32_Shdr* section_header = SectionHeader(section_id);
235     if (section_header->sh_type == SHT_NOBITS)  // E.g., .bss.
236       continue;
237     if (!IsRangeInBounds(section_header->sh_offset, section_header->sh_size))
238       return false;
239   }
240   return true;
241 }
242
243 bool DisassemblerElf32::CheckProgramSegmentRanges() {
244   for (Elf32_Half segment_id = 0; segment_id < ProgramSegmentHeaderCount();
245        ++segment_id) {
246     const Elf32_Phdr* segment_header = ProgramSegmentHeader(segment_id);
247     if (!IsRangeInBounds(segment_header->p_offset, segment_header->p_filesz))
248       return false;
249   }
250   return true;
251 }
252
253 void DisassemblerElf32::UpdateLength() {
254   Elf32_Off result = 0;
255
256   // Find the end of the last section.
257   for (Elf32_Half section_id = 0; section_id < SectionHeaderCount();
258        ++section_id) {
259     const Elf32_Shdr* section_header = SectionHeader(section_id);
260     if (section_header->sh_type == SHT_NOBITS)
261       continue;
262     DCHECK(IsRangeInBounds(section_header->sh_offset, section_header->sh_size));
263     Elf32_Off section_end = section_header->sh_offset + section_header->sh_size;
264     result = std::max(result, section_end);
265   }
266
267   // Find the end of the last segment.
268   for (Elf32_Half segment_id = 0; segment_id < ProgramSegmentHeaderCount();
269        ++segment_id) {
270     const Elf32_Phdr* segment_header = ProgramSegmentHeader(segment_id);
271     DCHECK(IsRangeInBounds(segment_header->p_offset, segment_header->p_filesz));
272     Elf32_Off segment_end = segment_header->p_offset + segment_header->p_filesz;
273     result = std::max(result, segment_end);
274   }
275
276   Elf32_Off section_table_end =
277       header_->e_shoff + (header_->e_shnum * sizeof(Elf32_Shdr));
278   result = std::max(result, section_table_end);
279
280   Elf32_Off segment_table_end =
281       header_->e_phoff + (header_->e_phnum * sizeof(Elf32_Phdr));
282   result = std::max(result, segment_table_end);
283
284   ReduceLength(result);
285 }
286
287 CheckBool DisassemblerElf32::SectionName(const Elf32_Shdr& shdr,
288                                          std::string* name) const {
289   DCHECK(name);
290   size_t string_pos = shdr.sh_name;
291   if (string_pos == 0) {
292     // Empty string by convention. Valid even if string section is empty.
293     name->clear();
294   } else {
295     if (string_pos >= default_string_section_size_)
296       return false;
297     // Safe because string section must terminate with null.
298     *name = default_string_section_ + string_pos;
299   }
300   return true;
301 }
302
303 CheckBool DisassemblerElf32::RVAsToFileOffsets(
304     const std::vector<RVA>& rvas,
305     std::vector<FileOffset>* file_offsets) const {
306   file_offsets->clear();
307   file_offsets->reserve(rvas.size());
308   for (RVA rva : rvas) {
309     FileOffset file_offset = RVAToFileOffset(rva);
310     if (file_offset == kNoFileOffset)
311       return false;
312     file_offsets->push_back(file_offset);
313   }
314   return true;
315 }
316
317 CheckBool DisassemblerElf32::RVAsToFileOffsets(
318     std::vector<std::unique_ptr<TypedRVA>>* typed_rvas) const {
319   for (auto& typed_rva : *typed_rvas) {
320     FileOffset file_offset = RVAToFileOffset(typed_rva->rva());
321     if (file_offset == kNoFileOffset)
322       return false;
323     typed_rva->set_file_offset(file_offset);
324   }
325   return true;
326 }
327
328 bool DisassemblerElf32::ExtractAbs32Locations() {
329   abs32_locations_.clear();
330
331   // Loop through sections for relocation sections
332   for (Elf32_Half section_id = 0; section_id < SectionHeaderCount();
333        ++section_id) {
334     const Elf32_Shdr* section_header = SectionHeader(section_id);
335
336     if (section_header->sh_type == SHT_REL) {
337       const Elf32_Rel* relocs_table =
338           reinterpret_cast<const Elf32_Rel*>(SectionBody(section_id));
339       // Reject if malformed.
340       if (section_header->sh_entsize != sizeof(Elf32_Rel))
341         return false;
342       if (section_header->sh_size % section_header->sh_entsize != 0)
343         return false;
344
345       int relocs_table_count =
346           section_header->sh_size / section_header->sh_entsize;
347
348       // Elf32_Word relocation_section_id = section_header->sh_info;
349
350       // Loop through relocation objects in the relocation section
351       for (int rel_id = 0; rel_id < relocs_table_count; ++rel_id) {
352         RVA rva;
353
354         // Quite a few of these conversions fail, and we simply skip
355         // them, that's okay.
356         if (RelToRVA(relocs_table[rel_id], &rva) && CheckSection(rva))
357           abs32_locations_.push_back(rva);
358       }
359     }
360   }
361
362   std::sort(abs32_locations_.begin(), abs32_locations_.end());
363   DCHECK(abs32_locations_.empty() || abs32_locations_.back() != kUnassignedRVA);
364   return true;
365 }
366
367 bool DisassemblerElf32::ExtractRel32Locations() {
368   rel32_locations_.clear();
369   bool found_rel32 = false;
370
371   // Loop through sections for relocation sections
372   for (Elf32_Half section_id = 0; section_id < SectionHeaderCount();
373        ++section_id) {
374     const Elf32_Shdr* section_header = SectionHeader(section_id);
375
376     // Some debug sections can have sh_type=SHT_PROGBITS but sh_addr=0.
377     if (section_header->sh_type != SHT_PROGBITS || section_header->sh_addr == 0)
378       continue;
379
380     // Heuristic: Only consider ".text" section.
381     std::string section_name;
382     if (!SectionName(*section_header, &section_name))
383       return false;
384     if (section_name != ".text")
385       continue;
386
387     found_rel32 = true;
388     if (!ParseRel32RelocsFromSection(section_header))
389       return false;
390   }
391   if (!found_rel32)
392     VLOG(1) << "Warning: Found no rel32 addresses. Missing .text section?";
393
394   std::sort(rel32_locations_.begin(), rel32_locations_.end(),
395             TypedRVA::IsLessThanByRVA);
396   DCHECK(rel32_locations_.empty() ||
397          rel32_locations_.back()->rva() != kUnassignedRVA);
398
399   return true;
400 }
401
402 RvaVisitor* DisassemblerElf32::CreateAbs32TargetRvaVisitor() {
403   return new RvaVisitor_Abs32(abs32_locations_, *this);
404 }
405
406 RvaVisitor* DisassemblerElf32::CreateRel32TargetRvaVisitor() {
407   return new Elf32RvaVisitor_Rel32(rel32_locations_);
408 }
409
410 void DisassemblerElf32::RemoveUnusedRel32Locations(AssemblyProgram* program) {
411   auto tail_it = rel32_locations_.begin();
412   for (auto head_it = rel32_locations_.begin();
413        head_it != rel32_locations_.end(); ++head_it) {
414     RVA target_rva = (*head_it)->rva() + (*head_it)->relative_target();
415     if (program->FindRel32Label(target_rva) == nullptr) {
416       // If address does not match a Label (because it was removed), deallocate.
417       (*head_it).reset(nullptr);
418     } else {
419       // Else squeeze nullptr to end to compactify.
420       if (tail_it != head_it)
421         (*tail_it).swap(*head_it);
422       ++tail_it;
423     }
424   }
425   rel32_locations_.resize(std::distance(rel32_locations_.begin(), tail_it));
426 }
427
428 InstructionGenerator DisassemblerElf32::GetInstructionGenerator(
429     AssemblyProgram* program) {
430   return base::BindRepeating(&DisassemblerElf32::ParseFile,
431                              base::Unretained(this), program);
432 }
433
434 CheckBool DisassemblerElf32::ParseFile(AssemblyProgram* program,
435                                        InstructionReceptor* receptor) const {
436   // Walk all the bytes in the file, whether or not in a section.
437   FileOffset file_offset = 0;
438
439   // File parsing follows file offset order, and we visit abs32 and rel32
440   // locations in lockstep. Therefore we need to extract and sort file offsets
441   // of all abs32 and rel32 locations. For abs32, we copy the offsets to a new
442   // array.
443   std::vector<FileOffset> abs_offsets;
444   if (!RVAsToFileOffsets(abs32_locations_, &abs_offsets))
445     return false;
446   std::sort(abs_offsets.begin(), abs_offsets.end());
447
448   // For rel32, TypedRVA (rather than raw offset) is stored, so sort-by-offset
449   // is performed in place to save memory. At the end of function we will
450   // sort-by-RVA.
451   if (!RVAsToFileOffsets(&rel32_locations_))
452     return false;
453   std::sort(rel32_locations_.begin(),
454             rel32_locations_.end(),
455             TypedRVA::IsLessThanByFileOffset);
456
457   std::vector<FileOffset>::iterator current_abs_offset = abs_offsets.begin();
458   std::vector<FileOffset>::iterator end_abs_offset = abs_offsets.end();
459
460   std::vector<std::unique_ptr<TypedRVA>>::iterator current_rel =
461       rel32_locations_.begin();
462   std::vector<std::unique_ptr<TypedRVA>>::iterator end_rel =
463       rel32_locations_.end();
464
465   // Visit section headers ordered by file offset.
466   for (Elf32_Half section_id : section_header_file_offset_order_) {
467     const Elf32_Shdr* section_header = SectionHeader(section_id);
468
469     if (section_header->sh_type == SHT_NOBITS)
470       continue;
471
472     if (!ParseSimpleRegion(file_offset, section_header->sh_offset, receptor))
473       return false;
474
475     file_offset = section_header->sh_offset;
476
477     switch (section_header->sh_type) {
478       case SHT_REL:
479         if (!ParseRelocationSection(section_header, receptor))
480           return false;
481         file_offset = section_header->sh_offset + section_header->sh_size;
482         break;
483       case SHT_PROGBITS:
484         if (!ParseProgbitsSection(section_header, &current_abs_offset,
485                                   end_abs_offset, &current_rel, end_rel,
486                                   program, receptor)) {
487           return false;
488         }
489         file_offset = section_header->sh_offset + section_header->sh_size;
490         break;
491       case SHT_INIT_ARRAY:
492         // Fall through
493       case SHT_FINI_ARRAY:
494         while (current_abs_offset != end_abs_offset &&
495                *current_abs_offset >= section_header->sh_offset &&
496                *current_abs_offset <
497                    section_header->sh_offset + section_header->sh_size) {
498           // Skip any abs_offsets appear in the unsupported INIT_ARRAY section
499           VLOG(1) << "Skipping relocation entry for unsupported section: "
500                   << section_header->sh_type;
501           ++current_abs_offset;
502         }
503         break;
504       default:
505         if (current_abs_offset != end_abs_offset &&
506             *current_abs_offset >= section_header->sh_offset &&
507             *current_abs_offset <
508                 section_header->sh_offset + section_header->sh_size) {
509           VLOG(1) << "Relocation address in unrecognized ELF section: "
510                   << section_header->sh_type;
511         }
512         break;
513     }
514   }
515
516   // Rest of the file past the last section
517   if (!ParseSimpleRegion(file_offset, length(), receptor))
518     return false;
519
520   // Restore original rel32 location order and sort by RVA order.
521   std::sort(rel32_locations_.begin(), rel32_locations_.end(),
522             TypedRVA::IsLessThanByRVA);
523
524   // Make certain we consume all of the relocations as expected
525   return (current_abs_offset == end_abs_offset);
526 }
527
528 CheckBool DisassemblerElf32::ParseProgbitsSection(
529     const Elf32_Shdr* section_header,
530     std::vector<FileOffset>::iterator* current_abs_offset,
531     std::vector<FileOffset>::iterator end_abs_offset,
532     std::vector<std::unique_ptr<TypedRVA>>::iterator* current_rel,
533     std::vector<std::unique_ptr<TypedRVA>>::iterator end_rel,
534     AssemblyProgram* program,
535     InstructionReceptor* receptor) const {
536   // Walk all the bytes in the file, whether or not in a section.
537   FileOffset file_offset = section_header->sh_offset;
538   FileOffset section_end = section_header->sh_offset + section_header->sh_size;
539
540   Elf32_Addr origin = section_header->sh_addr;
541   FileOffset origin_offset = section_header->sh_offset;
542   if (!receptor->EmitOrigin(origin))
543     return false;
544
545   while (file_offset < section_end) {
546     if (*current_abs_offset != end_abs_offset &&
547         file_offset > **current_abs_offset)
548       return false;
549
550     while (*current_rel != end_rel &&
551            file_offset > (**current_rel)->file_offset()) {
552       ++(*current_rel);
553     }
554
555     FileOffset next_relocation = section_end;
556
557     if (*current_abs_offset != end_abs_offset &&
558         next_relocation > **current_abs_offset)
559       next_relocation = **current_abs_offset;
560
561     // Rel offsets are heuristically derived, and might (incorrectly) overlap
562     // an Abs value, or the end of the section, so +3 to make sure there is
563     // room for the full 4 byte value.
564     if (*current_rel != end_rel &&
565         next_relocation > ((**current_rel)->file_offset() + 3))
566       next_relocation = (**current_rel)->file_offset();
567
568     if (next_relocation > file_offset) {
569       if (!ParseSimpleRegion(file_offset, next_relocation, receptor))
570         return false;
571
572       file_offset = next_relocation;
573       continue;
574     }
575
576     if (*current_abs_offset != end_abs_offset &&
577         file_offset == **current_abs_offset) {
578       RVA target_rva = PointerToTargetRVA(FileOffsetToPointer(file_offset));
579       DCHECK_NE(kNoRVA, target_rva);
580
581       Label* label = program->FindAbs32Label(target_rva);
582       CHECK(label);
583       if (!receptor->EmitAbs32(label))
584         return false;
585       file_offset += sizeof(RVA);
586       ++(*current_abs_offset);
587       continue;
588     }
589
590     if (*current_rel != end_rel &&
591         file_offset == (**current_rel)->file_offset()) {
592       uint32_t relative_target = (**current_rel)->relative_target();
593       CHECK_EQ(RVA(origin + (file_offset - origin_offset)),
594                (**current_rel)->rva());
595       // This cast is for 64 bit systems, and is only safe because we
596       // are working on 32 bit executables.
597       RVA target_rva = (RVA)(origin + (file_offset - origin_offset) +
598                              relative_target);
599
600       Label* label = program->FindRel32Label(target_rva);
601       CHECK(label);
602
603       if (!(**current_rel)->EmitInstruction(label, receptor))
604         return false;
605       file_offset += (**current_rel)->op_size();
606       ++(*current_rel);
607       continue;
608     }
609   }
610
611   // Rest of the section (if any)
612   return ParseSimpleRegion(file_offset, section_end, receptor);
613 }
614
615 CheckBool DisassemblerElf32::ParseSimpleRegion(
616     FileOffset start_file_offset,
617     FileOffset end_file_offset,
618     InstructionReceptor* receptor) const {
619   // Callers don't guarantee start < end
620   if (start_file_offset >= end_file_offset)
621     return true;
622
623   const size_t len = end_file_offset - start_file_offset;
624
625   if (!receptor->EmitMultipleBytes(FileOffsetToPointer(start_file_offset),
626                                    len)) {
627     return false;
628   }
629
630   return true;
631 }
632
633 CheckBool DisassemblerElf32::CheckSection(RVA rva) {
634   // Handle 32-bit references only.
635   constexpr uint8_t kWidth = 4;
636
637   FileOffset file_offset = RVAToFileOffset(rva);
638   if (file_offset == kNoFileOffset)
639     return false;
640
641   for (Elf32_Half section_id = 0; section_id < SectionHeaderCount();
642        ++section_id) {
643     const Elf32_Shdr* section_header = SectionHeader(section_id);
644     // Take account of pointer |kWidth|, and reject pointers that start within
645     // the section but whose span lies outside.
646     FileOffset start_offset = section_header->sh_offset;
647     if (file_offset < start_offset || section_header->sh_size < kWidth)
648       continue;
649     FileOffset end_offset = start_offset + section_header->sh_size - kWidth + 1;
650     if (file_offset >= end_offset)
651       continue;
652
653     switch (section_header->sh_type) {
654       case SHT_REL:  // Falls through.
655       case SHT_PROGBITS:
656         return true;
657     }
658   }
659
660   return false;
661 }
662
663 }  // namespace courgette