elftools 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/README.md +139 -0
- data/lib/elftools/constants.rb +182 -0
- data/lib/elftools/dynamic.rb +106 -0
- data/lib/elftools/elf_file.rb +277 -0
- data/lib/elftools/exceptions.rb +3 -0
- data/lib/elftools/lazy_array.rb +43 -0
- data/lib/elftools/note.rb +112 -0
- data/lib/elftools/sections/dynamic_section.rb +20 -0
- data/lib/elftools/sections/note_section.rb +25 -0
- data/lib/elftools/sections/null_section.rb +16 -0
- data/lib/elftools/sections/section.rb +44 -0
- data/lib/elftools/sections/sections.rb +34 -0
- data/lib/elftools/sections/str_tab_section.rb +27 -0
- data/lib/elftools/sections/sym_tab_section.rb +123 -0
- data/lib/elftools/segments/dynamic_segment.rb +18 -0
- data/lib/elftools/segments/interp_segment.rb +18 -0
- data/lib/elftools/segments/note_segment.rb +24 -0
- data/lib/elftools/segments/segment.rb +44 -0
- data/lib/elftools/segments/segments.rb +30 -0
- data/lib/elftools/structures.rb +133 -0
- data/lib/elftools/util.rb +51 -0
- data/lib/elftools/version.rb +3 -0
- data/lib/elftools.rb +9 -0
- metadata +153 -0
@@ -0,0 +1,277 @@
|
|
1
|
+
require 'elftools/constants'
|
2
|
+
require 'elftools/exceptions'
|
3
|
+
require 'elftools/lazy_array'
|
4
|
+
require 'elftools/sections/sections'
|
5
|
+
require 'elftools/segments/segments'
|
6
|
+
require 'elftools/structures'
|
7
|
+
|
8
|
+
module ELFTools
|
9
|
+
# The main class for using elftools.
|
10
|
+
class ELFFile
|
11
|
+
attr_reader :stream # @return [File] The +File+ object.
|
12
|
+
attr_reader :elf_class # @return [Integer] 32 or 64.
|
13
|
+
attr_reader :endian # @return [Symbol] +:little+ or +:big+.
|
14
|
+
|
15
|
+
# Instantiate an {ELFFile} object.
|
16
|
+
#
|
17
|
+
# @param [File] stream
|
18
|
+
# The +File+ object to be fetch information from.
|
19
|
+
# @example
|
20
|
+
# ELFFile.new(File.open('/bin/cat'))
|
21
|
+
# #=> #<ELFTools::ELFFile:0x00564b106c32a0 @elf_class=64, @endian=:little, @stream=#<File:/bin/cat>>
|
22
|
+
def initialize(stream)
|
23
|
+
@stream = stream
|
24
|
+
identify # fetch the most basic information
|
25
|
+
end
|
26
|
+
|
27
|
+
# Return the file header.
|
28
|
+
#
|
29
|
+
# Lazy loading.
|
30
|
+
# @retrn [ELFTools::ELF_Ehdr] The header.
|
31
|
+
def header
|
32
|
+
return @header if @header
|
33
|
+
stream.pos = 0
|
34
|
+
@header = ELF_Ehdr.new(endian: endian)
|
35
|
+
@header.elf_class = elf_class
|
36
|
+
@header.read(stream)
|
37
|
+
end
|
38
|
+
|
39
|
+
# Return the BuildID of ELF.
|
40
|
+
# @return [String, NilClass]
|
41
|
+
# BuildID in hex form will be returned.
|
42
|
+
# +nil+ is returned if the .note.gnu.build-id section
|
43
|
+
# is not found.
|
44
|
+
# @example
|
45
|
+
# elf.build_id
|
46
|
+
# #=> '73ab62cb7bc9959ce053c2b711322158708cdc07'
|
47
|
+
def build_id
|
48
|
+
section = section_by_name('.note.gnu.build-id')
|
49
|
+
return nil if section.nil?
|
50
|
+
note = section.notes.first
|
51
|
+
return nil if note.nil?
|
52
|
+
note.desc.unpack('H*').first
|
53
|
+
end
|
54
|
+
|
55
|
+
# Get Machine architecture.
|
56
|
+
#
|
57
|
+
# Mappings of architecture can be found
|
58
|
+
# in {ELFTools::Constants::EM.mapping}.
|
59
|
+
# @return [String]
|
60
|
+
# Name of architecture.
|
61
|
+
# @example
|
62
|
+
# elf.machine
|
63
|
+
# #=> 'Advanced Micro Devices X86-64'
|
64
|
+
def machine
|
65
|
+
ELFTools::Constants::EM.mapping(header.e_machine)
|
66
|
+
end
|
67
|
+
|
68
|
+
#========= method about sections
|
69
|
+
|
70
|
+
# Number of sections in this file.
|
71
|
+
# @return [Integer] The desired number.
|
72
|
+
# @example
|
73
|
+
# elf.num_sections
|
74
|
+
# #=> 29
|
75
|
+
def num_sections
|
76
|
+
header.e_shnum
|
77
|
+
end
|
78
|
+
|
79
|
+
# Acquire the section named as +name+.
|
80
|
+
# @param [String] name The desired section name.
|
81
|
+
# @return [ELFTools::Sections::Section, NilClass] The target section.
|
82
|
+
# @example
|
83
|
+
# elf.section_by_name('.note.gnu.build-id')
|
84
|
+
# #=> #<ELFTools::Sections::Section:0x005647b1282428>
|
85
|
+
# elf.section_by_name('')
|
86
|
+
# #=> #<ELFTools::Sections::NullSection:0x005647b11da110>
|
87
|
+
# elf.section_by_name('no such section')
|
88
|
+
# #=> nil
|
89
|
+
def section_by_name(name)
|
90
|
+
@section_name_map ||= {}
|
91
|
+
return @section_name_map[name] if @section_name_map[name]
|
92
|
+
each_sections do |section|
|
93
|
+
@section_name_map[section.name] = section
|
94
|
+
return section if section.name == name
|
95
|
+
end
|
96
|
+
nil
|
97
|
+
end
|
98
|
+
|
99
|
+
# Iterate all sections.
|
100
|
+
#
|
101
|
+
# All sections are lazy loading, the section
|
102
|
+
# only be created whenever accessing it.
|
103
|
+
# This method is useful for {#section_by_name}
|
104
|
+
# since not all sections need to be created.
|
105
|
+
# @param [Block] block
|
106
|
+
# Just like +Array#each+, you can give a block.
|
107
|
+
# @return [ Array<ELFTools::Sections::Section>]
|
108
|
+
# The whole sections will be returned.
|
109
|
+
def each_sections
|
110
|
+
Array.new(num_sections) do |i|
|
111
|
+
sec = section_at(i)
|
112
|
+
block_given? ? yield(sec) : sec
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
# Simply use {#sections} without giving block to get all sections.
|
117
|
+
alias sections each_sections
|
118
|
+
|
119
|
+
# Acquire the +n+-th section, 0-based.
|
120
|
+
#
|
121
|
+
# Sections are lazy loaded.
|
122
|
+
# @param [Integer] n The index.
|
123
|
+
# @return [ELFTools::Sections::Section, NilClass]
|
124
|
+
# The target section.
|
125
|
+
# If +n+ is out of bound, +nil+ is returned.
|
126
|
+
def section_at(n)
|
127
|
+
@sections ||= LazyArray.new(num_sections, &method(:create_section))
|
128
|
+
@sections[n]
|
129
|
+
end
|
130
|
+
|
131
|
+
# Get the string table section.
|
132
|
+
#
|
133
|
+
# This section is acquired by using the +e_shstrndx+
|
134
|
+
# in ELF header.
|
135
|
+
# @return [ELFTools::Sections::StrTabSection] The desired section.
|
136
|
+
def strtab_section
|
137
|
+
section_at(header.e_shstrndx)
|
138
|
+
end
|
139
|
+
|
140
|
+
#========= method about segments
|
141
|
+
|
142
|
+
# Number of segments in this file.
|
143
|
+
# @return [Integer] The desited number.
|
144
|
+
def num_segments
|
145
|
+
header.e_phnum
|
146
|
+
end
|
147
|
+
|
148
|
+
# Iterate all segments.
|
149
|
+
#
|
150
|
+
# All segments are lazy loading, the segment
|
151
|
+
# only be created whenever accessing it.
|
152
|
+
# This method is useful for {#segment_by_type}
|
153
|
+
# since not all segments need to be created.
|
154
|
+
# @param [Block] block
|
155
|
+
# Just like +Array#each+, you can give a block.
|
156
|
+
# @return [Array<ELFTools::Segments::Segment>]
|
157
|
+
# Whole segments will be returned.
|
158
|
+
def each_segments
|
159
|
+
Array.new(num_segments) do |i|
|
160
|
+
seg = segment_at(i)
|
161
|
+
block_given? ? yield(seg) : seg
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
# Simply use {#segments} without giving block to get all segments.
|
166
|
+
alias segments each_segments
|
167
|
+
|
168
|
+
# Get the first segment with +p_type=type+.
|
169
|
+
# The available types are listed in {ELFTools::Constants},
|
170
|
+
# starts with +PT_+.
|
171
|
+
#
|
172
|
+
# Notice: this method will return the first segment found,
|
173
|
+
# to found all segments with specific type you can use {#segments_by_type}.
|
174
|
+
# @param [Integer, Symbol, String] type
|
175
|
+
# See examples for clear usage.
|
176
|
+
# @return [ELFTools::Segments::Segment] The target segment.
|
177
|
+
# @example
|
178
|
+
# # type as an integer
|
179
|
+
# elf.segment_by_type(ELFTools::Constants::PT_NOTE)
|
180
|
+
# #=> #<ELFTools::Segments::NoteSegment:0x005629dda1e4f8>
|
181
|
+
#
|
182
|
+
# elf.segment_by_type(4) # PT_NOTE
|
183
|
+
# #=> #<ELFTools::Segments::NoteSegment:0x005629dda1e4f8>
|
184
|
+
#
|
185
|
+
# # type as a symbol
|
186
|
+
# elf.segment_by_type(:PT_NOTE)
|
187
|
+
# #=> #<ELFTools::Segments::NoteSegment:0x005629dda1e4f8>
|
188
|
+
#
|
189
|
+
# # you can do this
|
190
|
+
# elf.segment_by_type(:note) # will be transformed into `PT_NOTE`
|
191
|
+
# #=> #<ELFTools::Segments::NoteSegment:0x005629dda1e4f8>
|
192
|
+
#
|
193
|
+
# # type as a string
|
194
|
+
# elf.segment_by_type('PT_NOTE')
|
195
|
+
# #=> #<ELFTools::Segments::NoteSegment:0x005629dda1e4f8>
|
196
|
+
#
|
197
|
+
# # this is ok
|
198
|
+
# elf.segment_by_type('note') # will be tranformed into `PT_NOTE`
|
199
|
+
# #=> #<ELFTools::Segments::NoteSegment:0x005629dda1e4f8>
|
200
|
+
# @example
|
201
|
+
# elf.segment_by_type(1337)
|
202
|
+
# # ArgumentError: No constants in Constants::PT is 1337
|
203
|
+
#
|
204
|
+
# elf.segment_by_type('oao')
|
205
|
+
# # ArgumentError: No constants in Constants::PT named "PT_OAO"
|
206
|
+
# @example
|
207
|
+
# elf.segment_by_type(0)
|
208
|
+
# #=> nil # no such segment exists
|
209
|
+
def segment_by_type(type)
|
210
|
+
type = Util.to_constant(Constants::PT, type)
|
211
|
+
each_segments do |seg|
|
212
|
+
return seg if seg.header.p_type == type
|
213
|
+
end
|
214
|
+
nil
|
215
|
+
end
|
216
|
+
|
217
|
+
# Fetch all segments with specific type.
|
218
|
+
# If you want to find only one segment,
|
219
|
+
# use {#segment_by_type} instead.
|
220
|
+
# @param [Integer, Symbol, String] type
|
221
|
+
# The type needed, same format as {#segment_by_type}.
|
222
|
+
# @return [Array<ELFTools::Segments::Segment>] The target segments.
|
223
|
+
def segments_by_type(type)
|
224
|
+
type = Util.to_constant(Constants::PT, type)
|
225
|
+
segments.select { |segment| segment.header.p_type == type }
|
226
|
+
end
|
227
|
+
|
228
|
+
# Acquire the +n+-th segment, 0-based.
|
229
|
+
#
|
230
|
+
# Segments are lazy loaded.
|
231
|
+
# @param [Integer] n The index.
|
232
|
+
# @return [ELFTools::Segments::Segment, NilClass]
|
233
|
+
# The target segment.
|
234
|
+
# If +n+ is out of bound, +nil+ is returned.
|
235
|
+
def segment_at(n)
|
236
|
+
@segments ||= LazyArray.new(num_segments, &method(:create_segment))
|
237
|
+
@segments[n]
|
238
|
+
end
|
239
|
+
|
240
|
+
private
|
241
|
+
|
242
|
+
def identify
|
243
|
+
stream.pos = 0
|
244
|
+
magic = stream.read(4)
|
245
|
+
raise ELFError, "Invalid magic number #{magic.inspect}" unless magic == Constants::ELFMAG
|
246
|
+
ei_class = stream.read(1).ord
|
247
|
+
@elf_class = {
|
248
|
+
1 => 32,
|
249
|
+
2 => 64
|
250
|
+
}[ei_class]
|
251
|
+
raise ELFError, format('Invalid EI_CLASS "\x%02x"', ei_class) if elf_class.nil?
|
252
|
+
ei_data = stream.read(1).ord
|
253
|
+
@endian = {
|
254
|
+
1 => :little,
|
255
|
+
2 => :big
|
256
|
+
}[ei_data]
|
257
|
+
raise ELFError, format('Invalid EI_DATA "\x%02x"', ei_data) if endian.nil?
|
258
|
+
end
|
259
|
+
|
260
|
+
def create_section(n)
|
261
|
+
stream.pos = header.e_shoff + n * header.e_shentsize
|
262
|
+
shdr = ELF_Shdr.new(endian: endian)
|
263
|
+
shdr.elf_class = elf_class
|
264
|
+
shdr.read(stream)
|
265
|
+
Sections::Section.create(shdr, stream,
|
266
|
+
strtab: method(:strtab_section),
|
267
|
+
section_at: method(:section_at))
|
268
|
+
end
|
269
|
+
|
270
|
+
def create_segment(n)
|
271
|
+
stream.pos = header.e_phoff + n * header.e_phentsize
|
272
|
+
phdr = ELF_Phdr[elf_class].new(endian: endian)
|
273
|
+
phdr.elf_class = elf_class
|
274
|
+
Segments::Segment.create(phdr.read(stream), stream)
|
275
|
+
end
|
276
|
+
end
|
277
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module ELFTools
|
2
|
+
# A helper class for {ELFTools} easy to implement
|
3
|
+
# 'lazy loading' objects.
|
4
|
+
# Mainly used when loading sections, segments, and
|
5
|
+
# symbols.
|
6
|
+
class LazyArray
|
7
|
+
# Instantiate a {LazyArray} object.
|
8
|
+
# @param [Integer] size
|
9
|
+
# The size of array.
|
10
|
+
# @param [Block] block
|
11
|
+
# At first time accessing +i+-th element,
|
12
|
+
# block will be called as +block.call(i)+.
|
13
|
+
# @example
|
14
|
+
# arr = LazyArray.new(10) { |i| p i; i * i }
|
15
|
+
# p arr[2]
|
16
|
+
# # 2
|
17
|
+
# # 4
|
18
|
+
#
|
19
|
+
# p arr[3]
|
20
|
+
# # 3
|
21
|
+
# # 9
|
22
|
+
#
|
23
|
+
# p arr[3]
|
24
|
+
# # 9
|
25
|
+
def initialize(size, &block)
|
26
|
+
@internal = Array.new(size)
|
27
|
+
@block = block
|
28
|
+
end
|
29
|
+
|
30
|
+
# To access elements like a normal array.
|
31
|
+
#
|
32
|
+
# Elements are lazy loaded at the first time
|
33
|
+
# access it.
|
34
|
+
# @return [Object]
|
35
|
+
# The element, returned type is the
|
36
|
+
# return type of block given in {#initialize}.
|
37
|
+
def [](i)
|
38
|
+
# XXX: support negative index?
|
39
|
+
return nil if i < 0 || i >= @internal.size
|
40
|
+
@internal[i] ||= @block.call(i)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,112 @@
|
|
1
|
+
require 'elftools/structures'
|
2
|
+
require 'elftools/util'
|
3
|
+
|
4
|
+
module ELFTools
|
5
|
+
# Since both note sections and note segments
|
6
|
+
# refer to notes, this module defines common
|
7
|
+
# methods for {ELFTools::Sections::NoteSection} and {ELFTools::Segments::NoteSegment}.
|
8
|
+
#
|
9
|
+
# Notice: this module can only be included in {ELFTools::Sections::NoteSection} and
|
10
|
+
# {ELFTools::Segments::NoteSegment} since some methods assume some attributes already
|
11
|
+
# exist.
|
12
|
+
module Note
|
13
|
+
# Since size of {ELFTools::ELF_Nhdr} will not change no
|
14
|
+
# matter what endian and what arch, we can do this here.
|
15
|
+
# This value should equal to 12.
|
16
|
+
SIZE_OF_NHDR = ELF_Nhdr.new(endian: :little).num_bytes
|
17
|
+
|
18
|
+
# Iterate all notes in a note section or segment.
|
19
|
+
#
|
20
|
+
# Structure of notes are:
|
21
|
+
# +---------------+
|
22
|
+
# | Note 1 header |
|
23
|
+
# +---------------+
|
24
|
+
# | Note 1 name |
|
25
|
+
# +---------------+
|
26
|
+
# | Note 1 desc |
|
27
|
+
# +---------------+
|
28
|
+
# | Note 2 header |
|
29
|
+
# +---------------+
|
30
|
+
# | ... |
|
31
|
+
# +---------------+
|
32
|
+
#
|
33
|
+
# Notice: This method assume following methods exist:
|
34
|
+
# stream
|
35
|
+
# note_start
|
36
|
+
# note_total_size
|
37
|
+
# @return [Array<ELFTools::Note::Note>]
|
38
|
+
# The array of notes will be returned.
|
39
|
+
def each_notes
|
40
|
+
@notes_offset_map ||= {}
|
41
|
+
cur = note_start
|
42
|
+
notes = []
|
43
|
+
while cur < note_start + note_total_size
|
44
|
+
stream.pos = cur
|
45
|
+
@notes_offset_map[cur] ||= create_note(cur)
|
46
|
+
note = @notes_offset_map[cur]
|
47
|
+
# name and desc size needs to be 4-bytes align
|
48
|
+
name_size = Util.align(note.header.n_namesz, 2)
|
49
|
+
desc_size = Util.align(note.header.n_descsz, 2)
|
50
|
+
cur += SIZE_OF_NHDR + name_size + desc_size
|
51
|
+
notes << note
|
52
|
+
yield note if block_given?
|
53
|
+
end
|
54
|
+
notes
|
55
|
+
end
|
56
|
+
|
57
|
+
# Simply +#notes+ to get all notes.
|
58
|
+
alias notes each_notes
|
59
|
+
|
60
|
+
private
|
61
|
+
|
62
|
+
# Get the endian.
|
63
|
+
#
|
64
|
+
# Notice: This method assume method +header+ exists.
|
65
|
+
# @return [Symbol] +:little+ or +:big+.
|
66
|
+
def endian
|
67
|
+
header.class.self_endian
|
68
|
+
end
|
69
|
+
|
70
|
+
def create_note(cur)
|
71
|
+
nhdr = ELF_Nhdr.new(endian: endian).read(stream)
|
72
|
+
ELFTools::Note::Note.new(nhdr, stream, cur)
|
73
|
+
end
|
74
|
+
|
75
|
+
# Class of a note.
|
76
|
+
class Note
|
77
|
+
attr_reader :header # @return [ELFTools::ELF_Nhdr] Note header.
|
78
|
+
attr_reader :stream # @return [File] Streaming object.
|
79
|
+
attr_reader :offset # @return [Integer] Address of this note start, includes note header.
|
80
|
+
|
81
|
+
# Instantiate a {ELFTools::Note::Note} object.
|
82
|
+
# @param [ELF_Nhdr] header The note header.
|
83
|
+
# @param [File] stream Streaming object.
|
84
|
+
# @param [Integer] offset
|
85
|
+
# Start address of this note, includes the header.
|
86
|
+
def initialize(header, stream, offset)
|
87
|
+
@header = header
|
88
|
+
@stream = stream
|
89
|
+
@offset = offset
|
90
|
+
end
|
91
|
+
|
92
|
+
# Name of this note.
|
93
|
+
# @return [String] The name.
|
94
|
+
def name
|
95
|
+
return @name if @name
|
96
|
+
stream.pos = @offset + SIZE_OF_NHDR
|
97
|
+
@name = stream.read(header.n_namesz)[0..-2]
|
98
|
+
end
|
99
|
+
|
100
|
+
# Description of this note.
|
101
|
+
# @return [String] The description.
|
102
|
+
def desc
|
103
|
+
return @desc if @desc
|
104
|
+
stream.pos = @offset + SIZE_OF_NHDR + Util.align(header.n_namesz, 2)
|
105
|
+
@desc = stream.read(header.n_descsz)
|
106
|
+
end
|
107
|
+
|
108
|
+
# If someone likes to use full name.
|
109
|
+
alias description desc
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'elftools/dynamic'
|
2
|
+
require 'elftools/sections/section'
|
3
|
+
|
4
|
+
module ELFTools
|
5
|
+
module Sections
|
6
|
+
# Class for dynamic table section.
|
7
|
+
#
|
8
|
+
# This section should always be named .dynamic.
|
9
|
+
# This class knows how to get the list of dynamic tags.
|
10
|
+
class DynamicSection < Section
|
11
|
+
include ELFTools::Dynamic
|
12
|
+
|
13
|
+
# Get the start address of tags.
|
14
|
+
# @return [Integer] Start address of tags.
|
15
|
+
def tag_start
|
16
|
+
header.sh_offset
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'elftools/note'
|
2
|
+
require 'elftools/sections/section'
|
3
|
+
|
4
|
+
module ELFTools
|
5
|
+
module Sections
|
6
|
+
# Class of note section.
|
7
|
+
# Note section records notes
|
8
|
+
class NoteSection < Section
|
9
|
+
# Load note related methods.
|
10
|
+
include ELFTools::Note
|
11
|
+
|
12
|
+
# Address offset of notes start.
|
13
|
+
# @return [Integer] The offset.
|
14
|
+
def note_start
|
15
|
+
header.sh_offset
|
16
|
+
end
|
17
|
+
|
18
|
+
# The total size of notes in this section.
|
19
|
+
# @return [Integer] The size.
|
20
|
+
def note_total_size
|
21
|
+
header.sh_size
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'elftools/sections/section'
|
2
|
+
|
3
|
+
module ELFTools
|
4
|
+
module Sections
|
5
|
+
# Class of null section.
|
6
|
+
# Null section is for specific the end
|
7
|
+
# of linked list (+sh_link+) between sections.
|
8
|
+
class NullSection < Section
|
9
|
+
# Is this a null section?
|
10
|
+
# @return [Boolean] Yes it is.
|
11
|
+
def null?
|
12
|
+
true
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require 'elftools/constants'
|
2
|
+
module ELFTools
|
3
|
+
module Sections
|
4
|
+
# Base class of sections.
|
5
|
+
class Section
|
6
|
+
attr_reader :header # @return [ELFTools::ELF_Shdr] Section header.
|
7
|
+
attr_reader :stream # @return [File] Streaming object.
|
8
|
+
|
9
|
+
# Instantiate a {Section} object.
|
10
|
+
# @param [ELFTools::ELF_Shdr] header
|
11
|
+
# The section header object.
|
12
|
+
# @param [File] stream
|
13
|
+
# The streaming object for further dump.
|
14
|
+
# @param [ELFTools::Sections::StrTabSection, Proc] strtab
|
15
|
+
# The string table object. For fetching section names.
|
16
|
+
# If +Proc+ if given, it will call at the first
|
17
|
+
# time access +#name+.
|
18
|
+
def initialize(header, stream, strtab: nil, **_kwagrs)
|
19
|
+
@header = header
|
20
|
+
@stream = stream
|
21
|
+
@strtab = strtab
|
22
|
+
end
|
23
|
+
|
24
|
+
# Get name of this section.
|
25
|
+
# @return [String] The name.
|
26
|
+
def name
|
27
|
+
@name ||= @strtab.call.name_at(header.sh_name)
|
28
|
+
end
|
29
|
+
|
30
|
+
# Fetch data of this section.
|
31
|
+
# @return [String] Data.
|
32
|
+
def data
|
33
|
+
stream.pos = header.sh_offset
|
34
|
+
stream.read(header.sh_size)
|
35
|
+
end
|
36
|
+
|
37
|
+
# Is this a null section?
|
38
|
+
# @return [Boolean] No it's not.
|
39
|
+
def null?
|
40
|
+
false
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# Require this file to load all sections classes.
|
2
|
+
|
3
|
+
require 'elftools/sections/section'
|
4
|
+
|
5
|
+
require 'elftools/sections/dynamic_section'
|
6
|
+
require 'elftools/sections/note_section'
|
7
|
+
require 'elftools/sections/null_section'
|
8
|
+
require 'elftools/sections/str_tab_section'
|
9
|
+
require 'elftools/sections/sym_tab_section'
|
10
|
+
|
11
|
+
module ELFTools
|
12
|
+
# Defines different types of sections in this module.
|
13
|
+
module Sections
|
14
|
+
# Class methods of {Sections::Section}.
|
15
|
+
class << Section
|
16
|
+
# Use different class according to +header.sh_type+.
|
17
|
+
# @param [ELFTools::ELF_Shdr] header Section header.
|
18
|
+
# @param [File] stream Streaming object.
|
19
|
+
# @return [ELFTools::Sections::Section]
|
20
|
+
# Return object dependes on +header.sh_type+.
|
21
|
+
def create(header, stream, *args)
|
22
|
+
klass = case header.sh_type
|
23
|
+
when Constants::SHT_DYNAMIC then DynamicSection
|
24
|
+
when Constants::SHT_NULL then NullSection
|
25
|
+
when Constants::SHT_NOTE then NoteSection
|
26
|
+
when Constants::SHT_STRTAB then StrTabSection
|
27
|
+
when Constants::SHT_SYMTAB, Constants::SHT_DYNSYM then SymTabSection
|
28
|
+
else Section
|
29
|
+
end
|
30
|
+
klass.new(header, stream, *args)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'elftools/sections/section'
|
2
|
+
|
3
|
+
module ELFTools
|
4
|
+
module Sections
|
5
|
+
# Class of string table section.
|
6
|
+
# Usually for section .strtab and .dynstr,
|
7
|
+
# which record names.
|
8
|
+
class StrTabSection < Section
|
9
|
+
# Return the section or symbol name.
|
10
|
+
# @param [Integer] offset
|
11
|
+
# Usually from +shdr.sh_name+ or +sym.st_name+.
|
12
|
+
# @return [String] The name without null bytes.
|
13
|
+
def name_at(offset)
|
14
|
+
stream.pos = header.sh_offset + offset
|
15
|
+
# read until "\x00"
|
16
|
+
ret = ''
|
17
|
+
loop do
|
18
|
+
c = stream.read(1)
|
19
|
+
return nil if c.nil? # reach EOF
|
20
|
+
break if c == "\x00"
|
21
|
+
ret += c
|
22
|
+
end
|
23
|
+
ret
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|