Class: ELFTools::ELFFile
- Inherits:
-
Object
- Object
- ELFTools::ELFFile
- Defined in:
- lib/elftools/elf_file.rb
Overview
The main class for using elftools.
Instance Attribute Summary collapse
-
#elf_class ⇒ Integer
readonly
32 or 64.
-
#endian ⇒ Symbol
readonly
:littleor:big. -
#stream ⇒ #pos=, #read
readonly
The
Fileobject.
Instance Method Summary collapse
-
#build_id ⇒ String?
Return the BuildID of ELF.
-
#dynamic ⇒ ELFTools::Segments::DynamicSegment, ...
The dynamic tags of this file, read from the view that its type makes authoritative.
-
#each_section {|section| ... } ⇒ Enumerator<ELFTools::Sections::Section>, Array<ELFTools::Sections::Section>
(also: #each_sections)
Iterate all sections.
-
#each_segment {|segment| ... } ⇒ Array<ELFTools::Segments::Segment>
(also: #each_segments)
Iterate all segments.
-
#elf_type ⇒ String
Return the ELF type according to
e_type. -
#header ⇒ ELFTools::Structs::ELF_Ehdr
Return the file header.
-
#initialize(stream) ⇒ ELFFile
constructor
Instantiate an ELFFile object.
-
#machine ⇒ String
Get machine architecture.
-
#num_sections ⇒ Integer
Number of sections in this file.
-
#num_segments ⇒ Integer
Number of segments in this file.
-
#offset_from_vma(vma, size = 1) ⇒ Integer?
Get the offset related to file, given virtual memory address.
-
#patches ⇒ Hash{Integer => String}
The patch status.
-
#save(filename) ⇒ void
Apply patches and save as
filename. -
#section_at(n) ⇒ ELFTools::Sections::Section?
Acquire the +n+-th section, 0-based.
-
#section_by_name(name) ⇒ ELFTools::Sections::Section?
Acquire the section named as
name. -
#section_name_table ⇒ ELFTools::Sections::StrTabSection
The section the names of the sections are recorded in, which the ELF header names by index.
-
#sections ⇒ Array<ELFTools::Sections::Section>
Simply use #sections to get all sections.
-
#sections_by_type(type) {|section| ... } ⇒ Array<ELFTools::Sections::section>
Fetch all sections with specific type.
-
#segment_at(n) ⇒ ELFTools::Segments::Segment?
Acquire the +n+-th segment, 0-based.
-
#segment_by_type(type) ⇒ ELFTools::Segments::Segment
Get the first segment with
p_type=type. -
#segments ⇒ Array<ELFTools::Segments::Segment>
Simply use #segments to get all segments.
-
#segments_by_type(type) {|segment| ... } ⇒ Array<ELFTools::Segments::Segment>
Fetch all segments with specific type.
-
#vma_from_offset(offset, size = 1) ⇒ Integer?
Get virtual address given offset in file.
Constructor Details
#initialize(stream) ⇒ ELFFile
Instantiate an ELFTools::ELFFile object.
24 25 26 27 28 29 |
# File 'lib/elftools/elf_file.rb', line 24 def initialize(stream) @stream = stream # always set binmode if stream is an IO object. @stream.binmode if @stream.respond_to?(:binmode) identify # fetch the most basic information end |
Instance Attribute Details
#elf_class ⇒ Integer (readonly)
Returns 32 or 64.
14 15 16 |
# File 'lib/elftools/elf_file.rb', line 14 def elf_class @elf_class end |
#endian ⇒ Symbol (readonly)
Returns :little or :big.
15 16 17 |
# File 'lib/elftools/elf_file.rb', line 15 def endian @endian end |
#stream ⇒ #pos=, #read (readonly)
Returns The File object.
13 14 15 |
# File 'lib/elftools/elf_file.rb', line 13 def stream @stream end |
Instance Method Details
#build_id ⇒ String?
Return the BuildID of ELF.
52 53 54 55 56 57 58 59 60 |
# File 'lib/elftools/elf_file.rb', line 52 def build_id section = section_by_name('.note.gnu.build-id') return nil if section.nil? note = section.notes.first return nil if note.nil? note.desc.unpack1('H*') end |
#dynamic ⇒ ELFTools::Segments::DynamicSegment, ...
The dynamic tags of this file, read from the view that its type makes authoritative.
A relocatable file is linked by its sections, so its sections answer and any segment it carries is disregarded, being something no linker reads. An executable or a shared object is loaded by its segments alone, so the segment answers and the section recording the same tags is metadata a tool may have stripped or rewritten.
75 76 77 78 79 |
# File 'lib/elftools/elf_file.rb', line 75 def dynamic return sections_by_type(:dynamic).first if header.e_type.to_i == Constants::ET_REL segment_by_type(:dynamic) || sections_by_type(:dynamic).first end |
#each_section {|section| ... } ⇒ Enumerator<ELFTools::Sections::Section>, Array<ELFTools::Sections::Section> Also known as: each_sections
Iterate all sections.
All sections are lazy loading, the section only be created whenever accessing it. This method is useful for #section_by_name since not all sections need to be created.
148 149 150 151 152 153 154 |
# File 'lib/elftools/elf_file.rb', line 148 def each_section(&block) return enum_for(:each_section) unless block_given? Array.new(num_sections) do |i| section_at(i).tap(&block) end end |
#each_segment {|segment| ... } ⇒ Array<ELFTools::Segments::Segment> Also known as: each_segments
Iterate all segments.
All segments are lazy loading, the segment only be created whenever accessing it. This method is useful for #segment_by_type since not all segments need to be created.
238 239 240 241 242 243 244 |
# File 'lib/elftools/elf_file.rb', line 238 def each_segment(&block) return enum_for(:each_segment) unless block_given? Array.new(num_segments) do |i| segment_at(i).tap(&block) end end |
#elf_type ⇒ String
Return the ELF type according to e_type.
101 102 103 |
# File 'lib/elftools/elf_file.rb', line 101 def elf_type ELFTools::Constants::ET.mapping(header.e_type) end |
#header ⇒ ELFTools::Structs::ELF_Ehdr
Return the file header.
Lazy loading.
35 36 37 38 39 40 41 42 |
# File 'lib/elftools/elf_file.rb', line 35 def header return @header if defined?(@header) stream.pos = 0 @header = Structs::ELF_Ehdr.new(endian:, offset: stream.pos) @header.elf_class = elf_class @header.read(stream) end |
#machine ⇒ String
Get machine architecture.
Mappings of architecture can be found in Constants::EM.mapping.
90 91 92 |
# File 'lib/elftools/elf_file.rb', line 90 def machine ELFTools::Constants::EM.mapping(header.e_machine) end |
#num_sections ⇒ Integer
Number of sections in this file.
A file with more sections than the ELF header can count records a zero there and states the number in the first section header instead, which a file with no section headers at all records as well.
116 117 118 119 120 121 |
# File 'lib/elftools/elf_file.rb', line 116 def num_sections count = header.e_shnum.to_i return count unless count.zero? && !header.e_shoff.to_i.zero? first_section_header.sh_size.to_i end |
#num_segments ⇒ Integer
Number of segments in this file.
A file with more segments than the ELF header can count states the number in the first section header instead, as it does for the sections.
221 222 223 224 225 226 |
# File 'lib/elftools/elf_file.rb', line 221 def num_segments count = header.e_phnum.to_i return count unless count == Constants::PN_XNUM first_section_header.sh_info.to_i end |
#offset_from_vma(vma, size = 1) ⇒ Integer?
Get the offset related to file, given virtual memory address.
This method should work no matter ELF is a PIE or not. This method refers from (actually equals to) binutils/readelf.c#offset_from_vma.
339 340 341 342 343 344 345 |
# File 'lib/elftools/elf_file.rb', line 339 def offset_from_vma(vma, size = 1) segments_by_type(:load) do |seg| return seg.vma_to_offset(vma) if seg.vma_in?(vma, size) end nil end |
#patches ⇒ Hash{Integer => String}
The patch status.
366 367 368 369 370 371 372 373 374 |
# File 'lib/elftools/elf_file.rb', line 366 def patches patch = {} loaded_headers.each do |header| header.patches.each do |key, val| patch[key + header.offset] = val end end patch end |
#save(filename) ⇒ void
This method returns an undefined value.
Apply patches and save as filename.
380 381 382 383 384 385 386 387 |
# File 'lib/elftools/elf_file.rb', line 380 def save(filename) stream.pos = 0 all = stream.read.force_encoding('ascii-8bit') patches.each do |pos, val| all[pos, val.size] = val end File.binwrite(filename, all) end |
#section_at(n) ⇒ ELFTools::Sections::Section?
Acquire the +n+-th section, 0-based.
Sections are lazy loaded.
173 174 175 176 |
# File 'lib/elftools/elf_file.rb', line 173 def section_at(n) @sections ||= LazyArray.new(num_sections, &method(:create_section)) @sections[n] end |
#section_by_name(name) ⇒ ELFTools::Sections::Section?
Acquire the section named as name.
133 134 135 |
# File 'lib/elftools/elf_file.rb', line 133 def section_by_name(name) each_section.find { |sec| sec.name == name } end |
#section_name_table ⇒ ELFTools::Sections::StrTabSection
The section the names of the sections are recorded in, which the ELF header names by index.
It is not the section the names of the symbols are recorded in, which Sections::SymTabSection#symstr answers.
206 207 208 209 210 211 212 |
# File 'lib/elftools/elf_file.rb', line 206 def section_name_table index = header.e_shstrndx.to_i # An index too large for the ELF header is stated in the first section # header instead. index = first_section_header.sh_link.to_i if index == Constants::SHN_XINDEX section_at(index) end |
#sections ⇒ Array<ELFTools::Sections::Section>
Simply use #sections to get all sections.
162 163 164 |
# File 'lib/elftools/elf_file.rb', line 162 def sections each_section.to_a end |
#sections_by_type(type) {|section| ... } ⇒ Array<ELFTools::Sections::section>
Fetch all sections with specific type.
The available types are listed in Constants::PT. This method accept giving block.
192 193 194 195 |
# File 'lib/elftools/elf_file.rb', line 192 def sections_by_type(type, &) type = Util.to_constant(Constants::SHT, type) Util.select_by_type(each_section, type, &) end |
#segment_at(n) ⇒ ELFTools::Segments::Segment?
Acquire the +n+-th segment, 0-based.
Segments are lazy loaded.
324 325 326 327 |
# File 'lib/elftools/elf_file.rb', line 324 def segment_at(n) @segments ||= LazyArray.new(num_segments, &method(:create_segment)) @segments[n] end |
#segment_by_type(type) ⇒ ELFTools::Segments::Segment
This method will return the first segment found, to found all segments with specific type you can use #segments_by_type.
Get the first segment with p_type=type.
The available types are listed in Constants::PT.
297 298 299 300 |
# File 'lib/elftools/elf_file.rb', line 297 def segment_by_type(type) type = Util.to_constant(Constants::PT, type) each_segment.find { |seg| seg.header.p_type == type } end |
#segments ⇒ Array<ELFTools::Segments::Segment>
Simply use #segments to get all segments.
252 253 254 |
# File 'lib/elftools/elf_file.rb', line 252 def segments each_segment.to_a end |
#segments_by_type(type) {|segment| ... } ⇒ Array<ELFTools::Segments::Segment>
Fetch all segments with specific type.
If you want to find only one segment, use #segment_by_type instead. This method accept giving block.
312 313 314 315 |
# File 'lib/elftools/elf_file.rb', line 312 def segments_by_type(type, &) type = Util.to_constant(Constants::PT, type) Util.select_by_type(each_segment, type, &) end |
#vma_from_offset(offset, size = 1) ⇒ Integer?
Get virtual address given offset in file
356 357 358 359 360 361 362 |
# File 'lib/elftools/elf_file.rb', line 356 def vma_from_offset(offset, size = 1) segments_by_type(:load) do |seg| return seg.offset_to_vma(offset) if seg.offset_in?(offset, size) end nil end |