123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663 |
- // Copyright 2013 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
- #include "courgette/disassembler_elf_32.h"
- #include <algorithm>
- #include <iterator>
- #include "base/bind.h"
- #include "base/logging.h"
- #include "courgette/assembly_program.h"
- #include "courgette/courgette.h"
- namespace courgette {
- namespace {
- // Sorts |section_headers| by file offset and stores the resulting permutation
- // of section ids in |order|.
- std::vector<Elf32_Half> GetSectionHeaderFileOffsetOrder(
- const std::vector<Elf32_Shdr>& section_headers) {
- size_t size = section_headers.size();
- std::vector<Elf32_Half> order(size);
- for (size_t i = 0; i < size; ++i)
- order[i] = static_cast<Elf32_Half>(i);
- auto comp = [&](int idx1, int idx2) {
- return section_headers[idx1].sh_offset < section_headers[idx2].sh_offset;
- };
- std::stable_sort(order.begin(), order.end(), comp);
- return order;
- }
- } // namespace
- DisassemblerElf32::Elf32RvaVisitor_Rel32::Elf32RvaVisitor_Rel32(
- const std::vector<std::unique_ptr<TypedRVA>>& rva_locations)
- : VectorRvaVisitor<std::unique_ptr<TypedRVA>>(rva_locations) {
- }
- RVA DisassemblerElf32::Elf32RvaVisitor_Rel32::Get() const {
- return (*it_)->rva() + (*it_)->relative_target();
- }
- DisassemblerElf32::DisassemblerElf32(const uint8_t* start, size_t length)
- : Disassembler(start, length),
- header_(nullptr),
- section_header_table_size_(0),
- program_header_table_(nullptr),
- program_header_table_size_(0),
- default_string_section_(nullptr) {}
- RVA DisassemblerElf32::FileOffsetToRVA(FileOffset offset) const {
- // File offsets can be 64-bit values, but we are dealing with 32-bit
- // executables and so only need to support 32-bit file sizes.
- uint32_t offset32 = static_cast<uint32_t>(offset);
- // Visit section headers ordered by file offset.
- for (Elf32_Half section_id : section_header_file_offset_order_) {
- const Elf32_Shdr* section_header = SectionHeader(section_id);
- // These can appear to have a size in the file, but don't.
- if (section_header->sh_type == SHT_NOBITS)
- continue;
- Elf32_Off section_begin = section_header->sh_offset;
- Elf32_Off section_end = section_begin + section_header->sh_size;
- if (offset32 >= section_begin && offset32 < section_end) {
- return section_header->sh_addr + (offset32 - section_begin);
- }
- }
- return 0;
- }
- FileOffset DisassemblerElf32::RVAToFileOffset(RVA rva) const {
- for (Elf32_Half section_id = 0; section_id < SectionHeaderCount();
- ++section_id) {
- const Elf32_Shdr* section_header = SectionHeader(section_id);
- // These can appear to have a size in the file, but don't.
- if (section_header->sh_type == SHT_NOBITS)
- continue;
- Elf32_Addr begin = section_header->sh_addr;
- Elf32_Addr end = begin + section_header->sh_size;
- if (rva >= begin && rva < end)
- return section_header->sh_offset + (rva - begin);
- }
- return kNoFileOffset;
- }
- RVA DisassemblerElf32::PointerToTargetRVA(const uint8_t* p) const {
- // TODO(huangs): Add check (e.g., IsValidTargetRVA(), but more efficient).
- return Read32LittleEndian(p);
- }
- bool DisassemblerElf32::ParseHeader() {
- if (length() < sizeof(Elf32_Ehdr))
- return Bad("Too small");
- header_ = reinterpret_cast<const Elf32_Ehdr*>(start());
- // Perform DisassemblerElf32::QuickDetect() checks (with error messages).
- // Have magic for ELF header?
- if (header_->e_ident[EI_MAG0] != 0x7F || header_->e_ident[EI_MAG1] != 'E' ||
- header_->e_ident[EI_MAG2] != 'L' || header_->e_ident[EI_MAG3] != 'F') {
- return Bad("No Magic Number");
- }
- if (header_->e_ident[EI_CLASS] != ELFCLASS32 ||
- header_->e_ident[EI_DATA] != ELFDATA2LSB ||
- header_->e_machine != ElfEM()) {
- return Bad("Not a supported architecture");
- }
- if (header_->e_type != ET_EXEC && header_->e_type != ET_DYN)
- return Bad("Not an executable file or shared library");
- if (header_->e_version != 1 || header_->e_ident[EI_VERSION] != 1)
- return Bad("Unknown file version");
- if (header_->e_shentsize != sizeof(Elf32_Shdr))
- return Bad("Unexpected section header size");
- // Perform more complex checks, while extracting data.
- if (header_->e_shoff < sizeof(Elf32_Ehdr) ||
- !IsArrayInBounds(header_->e_shoff, header_->e_shnum,
- sizeof(Elf32_Shdr))) {
- return Bad("Out of bounds section header table");
- }
- // Extract |section_header_table_|, ordered by section id.
- const Elf32_Shdr* section_header_table_raw =
- reinterpret_cast<const Elf32_Shdr*>(
- FileOffsetToPointer(header_->e_shoff));
- section_header_table_size_ = header_->e_shnum;
- section_header_table_.assign(section_header_table_raw,
- section_header_table_raw + section_header_table_size_);
- if (!CheckSectionRanges())
- return Bad("Out of bound section");
- section_header_file_offset_order_ =
- GetSectionHeaderFileOffsetOrder(section_header_table_);
- if (header_->e_phoff < sizeof(Elf32_Ehdr) ||
- !IsArrayInBounds(header_->e_phoff, header_->e_phnum,
- sizeof(Elf32_Phdr))) {
- return Bad("Out of bounds program header table");
- }
- // Extract |program_header_table_|.
- program_header_table_size_ = header_->e_phnum;
- program_header_table_ = reinterpret_cast<const Elf32_Phdr*>(
- FileOffsetToPointer(header_->e_phoff));
- if (!CheckProgramSegmentRanges())
- return Bad("Out of bound segment");
- // Extract |default_string_section_|.
- Elf32_Half string_section_id = header_->e_shstrndx;
- if (string_section_id == SHN_UNDEF)
- return Bad("Missing string section");
- if (string_section_id >= header_->e_shnum)
- return Bad("Out of bounds string section index");
- if (SectionHeader(string_section_id)->sh_type != SHT_STRTAB)
- return Bad("Invalid string section");
- default_string_section_size_ = SectionHeader(string_section_id)->sh_size;
- default_string_section_ =
- reinterpret_cast<const char*>(SectionBody(string_section_id));
- // String section may be empty. If nonempty, then last byte must be null.
- if (default_string_section_size_ > 0) {
- if (default_string_section_[default_string_section_size_ - 1] != '\0')
- return Bad("String section does not terminate");
- }
- UpdateLength();
- return Good();
- }
- CheckBool DisassemblerElf32::IsValidTargetRVA(RVA rva) const {
- if (rva == kUnassignedRVA)
- return false;
- // |rva| is valid if it's contained in any program segment.
- for (Elf32_Half segment_id = 0; segment_id < ProgramSegmentHeaderCount();
- ++segment_id) {
- const Elf32_Phdr* segment_header = ProgramSegmentHeader(segment_id);
- if (segment_header->p_type != PT_LOAD)
- continue;
- Elf32_Addr begin = segment_header->p_vaddr;
- Elf32_Addr end = segment_header->p_vaddr + segment_header->p_memsz;
- if (rva >= begin && rva < end)
- return true;
- }
- return false;
- }
- // static
- bool DisassemblerElf32::QuickDetect(const uint8_t* start,
- size_t length,
- e_machine_values elf_em) {
- if (length < sizeof(Elf32_Ehdr))
- return false;
- const Elf32_Ehdr* header = reinterpret_cast<const Elf32_Ehdr*>(start);
- // Have magic for ELF header?
- if (header->e_ident[EI_MAG0] != 0x7F || header->e_ident[EI_MAG1] != 'E' ||
- header->e_ident[EI_MAG2] != 'L' || header->e_ident[EI_MAG3] != 'F') {
- return false;
- }
- if (header->e_ident[EI_CLASS] != ELFCLASS32 ||
- header->e_ident[EI_DATA] != ELFDATA2LSB || header->e_machine != elf_em) {
- return false;
- }
- if (header->e_type != ET_EXEC && header->e_type != ET_DYN)
- return false;
- if (header->e_version != 1 || header->e_ident[EI_VERSION] != 1)
- return false;
- if (header->e_shentsize != sizeof(Elf32_Shdr))
- return false;
- return true;
- }
- bool DisassemblerElf32::CheckSectionRanges() {
- for (Elf32_Half section_id = 0; section_id < SectionHeaderCount();
- ++section_id) {
- const Elf32_Shdr* section_header = SectionHeader(section_id);
- if (section_header->sh_type == SHT_NOBITS) // E.g., .bss.
- continue;
- if (!IsRangeInBounds(section_header->sh_offset, section_header->sh_size))
- return false;
- }
- return true;
- }
- bool DisassemblerElf32::CheckProgramSegmentRanges() {
- for (Elf32_Half segment_id = 0; segment_id < ProgramSegmentHeaderCount();
- ++segment_id) {
- const Elf32_Phdr* segment_header = ProgramSegmentHeader(segment_id);
- if (!IsRangeInBounds(segment_header->p_offset, segment_header->p_filesz))
- return false;
- }
- return true;
- }
- void DisassemblerElf32::UpdateLength() {
- Elf32_Off result = 0;
- // Find the end of the last section.
- for (Elf32_Half section_id = 0; section_id < SectionHeaderCount();
- ++section_id) {
- const Elf32_Shdr* section_header = SectionHeader(section_id);
- if (section_header->sh_type == SHT_NOBITS)
- continue;
- DCHECK(IsRangeInBounds(section_header->sh_offset, section_header->sh_size));
- Elf32_Off section_end = section_header->sh_offset + section_header->sh_size;
- result = std::max(result, section_end);
- }
- // Find the end of the last segment.
- for (Elf32_Half segment_id = 0; segment_id < ProgramSegmentHeaderCount();
- ++segment_id) {
- const Elf32_Phdr* segment_header = ProgramSegmentHeader(segment_id);
- DCHECK(IsRangeInBounds(segment_header->p_offset, segment_header->p_filesz));
- Elf32_Off segment_end = segment_header->p_offset + segment_header->p_filesz;
- result = std::max(result, segment_end);
- }
- Elf32_Off section_table_end =
- header_->e_shoff + (header_->e_shnum * sizeof(Elf32_Shdr));
- result = std::max(result, section_table_end);
- Elf32_Off segment_table_end =
- header_->e_phoff + (header_->e_phnum * sizeof(Elf32_Phdr));
- result = std::max(result, segment_table_end);
- ReduceLength(result);
- }
- CheckBool DisassemblerElf32::SectionName(const Elf32_Shdr& shdr,
- std::string* name) const {
- DCHECK(name);
- size_t string_pos = shdr.sh_name;
- if (string_pos == 0) {
- // Empty string by convention. Valid even if string section is empty.
- name->clear();
- } else {
- if (string_pos >= default_string_section_size_)
- return false;
- // Safe because string section must terminate with null.
- *name = default_string_section_ + string_pos;
- }
- return true;
- }
- CheckBool DisassemblerElf32::RVAsToFileOffsets(
- const std::vector<RVA>& rvas,
- std::vector<FileOffset>* file_offsets) const {
- file_offsets->clear();
- file_offsets->reserve(rvas.size());
- for (RVA rva : rvas) {
- FileOffset file_offset = RVAToFileOffset(rva);
- if (file_offset == kNoFileOffset)
- return false;
- file_offsets->push_back(file_offset);
- }
- return true;
- }
- CheckBool DisassemblerElf32::RVAsToFileOffsets(
- std::vector<std::unique_ptr<TypedRVA>>* typed_rvas) const {
- for (auto& typed_rva : *typed_rvas) {
- FileOffset file_offset = RVAToFileOffset(typed_rva->rva());
- if (file_offset == kNoFileOffset)
- return false;
- typed_rva->set_file_offset(file_offset);
- }
- return true;
- }
- bool DisassemblerElf32::ExtractAbs32Locations() {
- abs32_locations_.clear();
- // Loop through sections for relocation sections
- for (Elf32_Half section_id = 0; section_id < SectionHeaderCount();
- ++section_id) {
- const Elf32_Shdr* section_header = SectionHeader(section_id);
- if (section_header->sh_type == SHT_REL) {
- const Elf32_Rel* relocs_table =
- reinterpret_cast<const Elf32_Rel*>(SectionBody(section_id));
- // Reject if malformed.
- if (section_header->sh_entsize != sizeof(Elf32_Rel))
- return false;
- if (section_header->sh_size % section_header->sh_entsize != 0)
- return false;
- int relocs_table_count =
- section_header->sh_size / section_header->sh_entsize;
- // Elf32_Word relocation_section_id = section_header->sh_info;
- // Loop through relocation objects in the relocation section
- for (int rel_id = 0; rel_id < relocs_table_count; ++rel_id) {
- RVA rva;
- // Quite a few of these conversions fail, and we simply skip
- // them, that's okay.
- if (RelToRVA(relocs_table[rel_id], &rva) && CheckSection(rva))
- abs32_locations_.push_back(rva);
- }
- }
- }
- std::sort(abs32_locations_.begin(), abs32_locations_.end());
- DCHECK(abs32_locations_.empty() || abs32_locations_.back() != kUnassignedRVA);
- return true;
- }
- bool DisassemblerElf32::ExtractRel32Locations() {
- rel32_locations_.clear();
- bool found_rel32 = false;
- // Loop through sections for relocation sections
- for (Elf32_Half section_id = 0; section_id < SectionHeaderCount();
- ++section_id) {
- const Elf32_Shdr* section_header = SectionHeader(section_id);
- // Some debug sections can have sh_type=SHT_PROGBITS but sh_addr=0.
- if (section_header->sh_type != SHT_PROGBITS || section_header->sh_addr == 0)
- continue;
- // Heuristic: Only consider ".text" section.
- std::string section_name;
- if (!SectionName(*section_header, §ion_name))
- return false;
- if (section_name != ".text")
- continue;
- found_rel32 = true;
- if (!ParseRel32RelocsFromSection(section_header))
- return false;
- }
- if (!found_rel32)
- VLOG(1) << "Warning: Found no rel32 addresses. Missing .text section?";
- std::sort(rel32_locations_.begin(), rel32_locations_.end(),
- TypedRVA::IsLessThanByRVA);
- DCHECK(rel32_locations_.empty() ||
- rel32_locations_.back()->rva() != kUnassignedRVA);
- return true;
- }
- RvaVisitor* DisassemblerElf32::CreateAbs32TargetRvaVisitor() {
- return new RvaVisitor_Abs32(abs32_locations_, *this);
- }
- RvaVisitor* DisassemblerElf32::CreateRel32TargetRvaVisitor() {
- return new Elf32RvaVisitor_Rel32(rel32_locations_);
- }
- void DisassemblerElf32::RemoveUnusedRel32Locations(AssemblyProgram* program) {
- auto tail_it = rel32_locations_.begin();
- for (auto head_it = rel32_locations_.begin();
- head_it != rel32_locations_.end(); ++head_it) {
- RVA target_rva = (*head_it)->rva() + (*head_it)->relative_target();
- if (program->FindRel32Label(target_rva) == nullptr) {
- // If address does not match a Label (because it was removed), deallocate.
- (*head_it).reset(nullptr);
- } else {
- // Else squeeze nullptr to end to compactify.
- if (tail_it != head_it)
- (*tail_it).swap(*head_it);
- ++tail_it;
- }
- }
- rel32_locations_.resize(std::distance(rel32_locations_.begin(), tail_it));
- }
- InstructionGenerator DisassemblerElf32::GetInstructionGenerator(
- AssemblyProgram* program) {
- return base::BindRepeating(&DisassemblerElf32::ParseFile,
- base::Unretained(this), program);
- }
- CheckBool DisassemblerElf32::ParseFile(AssemblyProgram* program,
- InstructionReceptor* receptor) const {
- // Walk all the bytes in the file, whether or not in a section.
- FileOffset file_offset = 0;
- // File parsing follows file offset order, and we visit abs32 and rel32
- // locations in lockstep. Therefore we need to extract and sort file offsets
- // of all abs32 and rel32 locations. For abs32, we copy the offsets to a new
- // array.
- std::vector<FileOffset> abs_offsets;
- if (!RVAsToFileOffsets(abs32_locations_, &abs_offsets))
- return false;
- std::sort(abs_offsets.begin(), abs_offsets.end());
- // For rel32, TypedRVA (rather than raw offset) is stored, so sort-by-offset
- // is performed in place to save memory. At the end of function we will
- // sort-by-RVA.
- if (!RVAsToFileOffsets(&rel32_locations_))
- return false;
- std::sort(rel32_locations_.begin(),
- rel32_locations_.end(),
- TypedRVA::IsLessThanByFileOffset);
- std::vector<FileOffset>::iterator current_abs_offset = abs_offsets.begin();
- std::vector<FileOffset>::iterator end_abs_offset = abs_offsets.end();
- std::vector<std::unique_ptr<TypedRVA>>::iterator current_rel =
- rel32_locations_.begin();
- std::vector<std::unique_ptr<TypedRVA>>::iterator end_rel =
- rel32_locations_.end();
- // Visit section headers ordered by file offset.
- for (Elf32_Half section_id : section_header_file_offset_order_) {
- const Elf32_Shdr* section_header = SectionHeader(section_id);
- if (section_header->sh_type == SHT_NOBITS)
- continue;
- if (!ParseSimpleRegion(file_offset, section_header->sh_offset, receptor))
- return false;
- file_offset = section_header->sh_offset;
- switch (section_header->sh_type) {
- case SHT_REL:
- if (!ParseRelocationSection(section_header, receptor))
- return false;
- file_offset = section_header->sh_offset + section_header->sh_size;
- break;
- case SHT_PROGBITS:
- if (!ParseProgbitsSection(section_header, ¤t_abs_offset,
- end_abs_offset, ¤t_rel, end_rel,
- program, receptor)) {
- return false;
- }
- file_offset = section_header->sh_offset + section_header->sh_size;
- break;
- case SHT_INIT_ARRAY:
- // Fall through
- case SHT_FINI_ARRAY:
- while (current_abs_offset != end_abs_offset &&
- *current_abs_offset >= section_header->sh_offset &&
- *current_abs_offset <
- section_header->sh_offset + section_header->sh_size) {
- // Skip any abs_offsets appear in the unsupported INIT_ARRAY section
- VLOG(1) << "Skipping relocation entry for unsupported section: "
- << section_header->sh_type;
- ++current_abs_offset;
- }
- break;
- default:
- if (current_abs_offset != end_abs_offset &&
- *current_abs_offset >= section_header->sh_offset &&
- *current_abs_offset <
- section_header->sh_offset + section_header->sh_size) {
- VLOG(1) << "Relocation address in unrecognized ELF section: "
- << section_header->sh_type;
- }
- break;
- }
- }
- // Rest of the file past the last section
- if (!ParseSimpleRegion(file_offset, length(), receptor))
- return false;
- // Restore original rel32 location order and sort by RVA order.
- std::sort(rel32_locations_.begin(), rel32_locations_.end(),
- TypedRVA::IsLessThanByRVA);
- // Make certain we consume all of the relocations as expected
- return (current_abs_offset == end_abs_offset);
- }
- CheckBool DisassemblerElf32::ParseProgbitsSection(
- const Elf32_Shdr* section_header,
- std::vector<FileOffset>::iterator* current_abs_offset,
- std::vector<FileOffset>::iterator end_abs_offset,
- std::vector<std::unique_ptr<TypedRVA>>::iterator* current_rel,
- std::vector<std::unique_ptr<TypedRVA>>::iterator end_rel,
- AssemblyProgram* program,
- InstructionReceptor* receptor) const {
- // Walk all the bytes in the file, whether or not in a section.
- FileOffset file_offset = section_header->sh_offset;
- FileOffset section_end = section_header->sh_offset + section_header->sh_size;
- Elf32_Addr origin = section_header->sh_addr;
- FileOffset origin_offset = section_header->sh_offset;
- if (!receptor->EmitOrigin(origin))
- return false;
- while (file_offset < section_end) {
- if (*current_abs_offset != end_abs_offset &&
- file_offset > **current_abs_offset)
- return false;
- while (*current_rel != end_rel &&
- file_offset > (**current_rel)->file_offset()) {
- ++(*current_rel);
- }
- FileOffset next_relocation = section_end;
- if (*current_abs_offset != end_abs_offset &&
- next_relocation > **current_abs_offset)
- next_relocation = **current_abs_offset;
- // Rel offsets are heuristically derived, and might (incorrectly) overlap
- // an Abs value, or the end of the section, so +3 to make sure there is
- // room for the full 4 byte value.
- if (*current_rel != end_rel &&
- next_relocation > ((**current_rel)->file_offset() + 3))
- next_relocation = (**current_rel)->file_offset();
- if (next_relocation > file_offset) {
- if (!ParseSimpleRegion(file_offset, next_relocation, receptor))
- return false;
- file_offset = next_relocation;
- continue;
- }
- if (*current_abs_offset != end_abs_offset &&
- file_offset == **current_abs_offset) {
- RVA target_rva = PointerToTargetRVA(FileOffsetToPointer(file_offset));
- DCHECK_NE(kNoRVA, target_rva);
- Label* label = program->FindAbs32Label(target_rva);
- CHECK(label);
- if (!receptor->EmitAbs32(label))
- return false;
- file_offset += sizeof(RVA);
- ++(*current_abs_offset);
- continue;
- }
- if (*current_rel != end_rel &&
- file_offset == (**current_rel)->file_offset()) {
- uint32_t relative_target = (**current_rel)->relative_target();
- CHECK_EQ(RVA(origin + (file_offset - origin_offset)),
- (**current_rel)->rva());
- // This cast is for 64 bit systems, and is only safe because we
- // are working on 32 bit executables.
- RVA target_rva = (RVA)(origin + (file_offset - origin_offset) +
- relative_target);
- Label* label = program->FindRel32Label(target_rva);
- CHECK(label);
- if (!(**current_rel)->EmitInstruction(label, receptor))
- return false;
- file_offset += (**current_rel)->op_size();
- ++(*current_rel);
- continue;
- }
- }
- // Rest of the section (if any)
- return ParseSimpleRegion(file_offset, section_end, receptor);
- }
- CheckBool DisassemblerElf32::ParseSimpleRegion(
- FileOffset start_file_offset,
- FileOffset end_file_offset,
- InstructionReceptor* receptor) const {
- // Callers don't guarantee start < end
- if (start_file_offset >= end_file_offset)
- return true;
- const size_t len = end_file_offset - start_file_offset;
- if (!receptor->EmitMultipleBytes(FileOffsetToPointer(start_file_offset),
- len)) {
- return false;
- }
- return true;
- }
- CheckBool DisassemblerElf32::CheckSection(RVA rva) {
- // Handle 32-bit references only.
- constexpr uint8_t kWidth = 4;
- FileOffset file_offset = RVAToFileOffset(rva);
- if (file_offset == kNoFileOffset)
- return false;
- for (Elf32_Half section_id = 0; section_id < SectionHeaderCount();
- ++section_id) {
- const Elf32_Shdr* section_header = SectionHeader(section_id);
- // Take account of pointer |kWidth|, and reject pointers that start within
- // the section but whose span lies outside.
- FileOffset start_offset = section_header->sh_offset;
- if (file_offset < start_offset || section_header->sh_size < kWidth)
- continue;
- FileOffset end_offset = start_offset + section_header->sh_size - kWidth + 1;
- if (file_offset >= end_offset)
- continue;
- switch (section_header->sh_type) {
- case SHT_REL: // Falls through.
- case SHT_PROGBITS:
- return true;
- }
- }
- return false;
- }
- } // namespace courgette
|