elftools 1.3.1 → 2.0.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 +4 -4
- data/README.md +111 -7
- data/lib/elftools/constants/machine.rb +248 -0
- data/lib/elftools/constants/machine_names.rb +246 -0
- data/lib/elftools/constants/relocation/aarch64.rb +213 -0
- data/lib/elftools/constants/relocation/alpha.rb +47 -0
- data/lib/elftools/constants/relocation/amdgpu.rb +28 -0
- data/lib/elftools/constants/relocation/arm.rb +150 -0
- data/lib/elftools/constants/relocation/avr.rb +51 -0
- data/lib/elftools/constants/relocation/bfin.rb +72 -0
- data/lib/elftools/constants/relocation/bpf.rb +21 -0
- data/lib/elftools/constants/relocation/cr16.rb +46 -0
- data/lib/elftools/constants/relocation/cris.rb +46 -0
- data/lib/elftools/constants/relocation/crx.rb +35 -0
- data/lib/elftools/constants/relocation/csky.rb +79 -0
- data/lib/elftools/constants/relocation/d10v.rb +23 -0
- data/lib/elftools/constants/relocation/d30v.rb +27 -0
- data/lib/elftools/constants/relocation/dlx.rb +24 -0
- data/lib/elftools/constants/relocation/epiphany.rb +28 -0
- data/lib/elftools/constants/relocation/fr30.rb +27 -0
- data/lib/elftools/constants/relocation/frv.rb +57 -0
- data/lib/elftools/constants/relocation/ft32.rb +27 -0
- data/lib/elftools/constants/relocation/h8.rb +69 -0
- data/lib/elftools/constants/relocation/hppa.rb +135 -0
- data/lib/elftools/constants/relocation/i370.rb +26 -0
- data/lib/elftools/constants/relocation/i386.rb +59 -0
- data/lib/elftools/constants/relocation/i860.rb +48 -0
- data/lib/elftools/constants/relocation/i960.rb +22 -0
- data/lib/elftools/constants/relocation/ia64.rb +117 -0
- data/lib/elftools/constants/relocation/ip2k.rb +29 -0
- data/lib/elftools/constants/relocation/iq2000.rb +27 -0
- data/lib/elftools/constants/relocation/kvx.rb +97 -0
- data/lib/elftools/constants/relocation/lm32.rb +32 -0
- data/lib/elftools/constants/relocation/loongarch.rb +144 -0
- data/lib/elftools/constants/relocation/m32c.rb +27 -0
- data/lib/elftools/constants/relocation/m32r.rb +57 -0
- data/lib/elftools/constants/relocation/m68hc11.rb +35 -0
- data/lib/elftools/constants/relocation/m68k.rb +57 -0
- data/lib/elftools/constants/relocation/mcore.rb +27 -0
- data/lib/elftools/constants/relocation/mep.rb +36 -0
- data/lib/elftools/constants/relocation/metag.rb +63 -0
- data/lib/elftools/constants/relocation/microblaze.rb +48 -0
- data/lib/elftools/constants/relocation/mips.rb +125 -0
- data/lib/elftools/constants/relocation/mmix.rb +51 -0
- data/lib/elftools/constants/relocation/mn10200.rb +22 -0
- data/lib/elftools/constants/relocation/mn10300.rb +49 -0
- data/lib/elftools/constants/relocation/moxie.rb +17 -0
- data/lib/elftools/constants/relocation/msp430.rb +27 -0
- data/lib/elftools/constants/relocation/msp430x.rb +37 -0
- data/lib/elftools/constants/relocation/mt.rb +21 -0
- data/lib/elftools/constants/relocation/nds32.rb +167 -0
- data/lib/elftools/constants/relocation/nfp.rb +41 -0
- data/lib/elftools/constants/relocation/nfp3200.rb +46 -0
- data/lib/elftools/constants/relocation/nios2.rb +74 -0
- data/lib/elftools/constants/relocation/or1k.rb +69 -0
- data/lib/elftools/constants/relocation/pj.rb +24 -0
- data/lib/elftools/constants/relocation/ppc.rb +131 -0
- data/lib/elftools/constants/relocation/ppc64.rb +177 -0
- data/lib/elftools/constants/relocation/pru.rb +31 -0
- data/lib/elftools/constants/relocation/riscv.rb +74 -0
- data/lib/elftools/constants/relocation/rl78.rb +70 -0
- data/lib/elftools/constants/relocation/rx.rb +81 -0
- data/lib/elftools/constants/relocation/s12z.rb +22 -0
- data/lib/elftools/constants/relocation/s390.rb +82 -0
- data/lib/elftools/constants/relocation/score.rb +36 -0
- data/lib/elftools/constants/relocation/sh.rb +124 -0
- data/lib/elftools/constants/relocation/sparc.rb +108 -0
- data/lib/elftools/constants/relocation/spu.rb +32 -0
- data/lib/elftools/constants/relocation/tic6x.rb +48 -0
- data/lib/elftools/constants/relocation/tilegx.rb +134 -0
- data/lib/elftools/constants/relocation/tilepro.rb +105 -0
- data/lib/elftools/constants/relocation/v800.rb +101 -0
- data/lib/elftools/constants/relocation/v850.rb +66 -0
- data/lib/elftools/constants/relocation/vax.rb +29 -0
- data/lib/elftools/constants/relocation/visium.rb +30 -0
- data/lib/elftools/constants/relocation/wasm32.rb +16 -0
- data/lib/elftools/constants/relocation/x86_64.rb +68 -0
- data/lib/elftools/constants/relocation/xgate.rb +34 -0
- data/lib/elftools/constants/relocation/xstormy16.rb +29 -0
- data/lib/elftools/constants/relocation/xtensa.rb +75 -0
- data/lib/elftools/constants/relocation/z80.rb +28 -0
- data/lib/elftools/constants/relocation.rb +181 -0
- data/lib/elftools/constants.rb +124 -231
- data/lib/elftools/dynamic/hash_table.rb +216 -0
- data/lib/elftools/dynamic/string_table.rb +30 -0
- data/lib/elftools/dynamic/symbols.rb +146 -0
- data/lib/elftools/dynamic/tag.rb +66 -0
- data/lib/elftools/dynamic.rb +102 -62
- data/lib/elftools/elf_file.rb +73 -22
- data/lib/elftools/lazy_array.rb +42 -4
- data/lib/elftools/note.rb +6 -3
- data/lib/elftools/relocation.rb +94 -0
- data/lib/elftools/sections/dynamic_section.rb +13 -0
- data/lib/elftools/sections/relocation_section.rb +24 -43
- data/lib/elftools/sections/section.rb +4 -4
- data/lib/elftools/sections/sym_tab_section.rb +14 -34
- data/lib/elftools/sections/symbol.rb +112 -0
- data/lib/elftools/segments/dynamic_segment.rb +1 -0
- data/lib/elftools/segments/load_segment.rb +33 -5
- data/lib/elftools/segments/segment.rb +8 -4
- data/lib/elftools/structs.rb +24 -3
- data/lib/elftools/util.rb +1 -1
- data/lib/elftools/version.rb +1 -1
- metadata +101 -11
data/lib/elftools/elf_file.rb
CHANGED
|
@@ -59,6 +59,25 @@ module ELFTools
|
|
|
59
59
|
note.desc.unpack1('H*')
|
|
60
60
|
end
|
|
61
61
|
|
|
62
|
+
# The dynamic tags of this file, read from the view that its type makes
|
|
63
|
+
# authoritative.
|
|
64
|
+
#
|
|
65
|
+
# A relocatable file is linked by its sections, so its sections answer and
|
|
66
|
+
# any segment it carries is disregarded, being something no linker reads.
|
|
67
|
+
# An executable or a shared object is loaded by its segments alone, so the
|
|
68
|
+
# segment answers and the section recording the same tags is metadata a
|
|
69
|
+
# tool may have stripped or rewritten.
|
|
70
|
+
# @return [ELFTools::Segments::DynamicSegment, ELFTools::Sections::DynamicSection, nil]
|
|
71
|
+
# The tags, +nil+ if the view that decides records none.
|
|
72
|
+
# @example
|
|
73
|
+
# elf.dynamic.tag_by_type(:needed).name
|
|
74
|
+
# #=> 'libc.so.6'
|
|
75
|
+
def dynamic
|
|
76
|
+
return sections_by_type(:dynamic).first if header.e_type.to_i == Constants::ET_REL
|
|
77
|
+
|
|
78
|
+
segment_by_type(:dynamic) || sections_by_type(:dynamic).first
|
|
79
|
+
end
|
|
80
|
+
|
|
62
81
|
# Get machine architecture.
|
|
63
82
|
#
|
|
64
83
|
# Mappings of architecture can be found
|
|
@@ -67,7 +86,7 @@ module ELFTools
|
|
|
67
86
|
# Name of architecture.
|
|
68
87
|
# @example
|
|
69
88
|
# elf.machine
|
|
70
|
-
# #=> 'Advanced Micro Devices X86-64'
|
|
89
|
+
# #=> 'Advanced Micro Devices X86-64 processor'
|
|
71
90
|
def machine
|
|
72
91
|
ELFTools::Constants::EM.mapping(header.e_machine)
|
|
73
92
|
end
|
|
@@ -105,7 +124,7 @@ module ELFTools
|
|
|
105
124
|
# elf.section_by_name('no such section')
|
|
106
125
|
# #=> nil
|
|
107
126
|
def section_by_name(name)
|
|
108
|
-
|
|
127
|
+
each_section.find { |sec| sec.name == name }
|
|
109
128
|
end
|
|
110
129
|
|
|
111
130
|
# Iterate all sections.
|
|
@@ -119,19 +138,22 @@ module ELFTools
|
|
|
119
138
|
# @return [Enumerator<ELFTools::Sections::Section>, Array<ELFTools::Sections::Section>]
|
|
120
139
|
# As +Array#each+, if block is not given, a enumerator will be returned,
|
|
121
140
|
# otherwise, the whole sections will be returned.
|
|
122
|
-
def
|
|
123
|
-
return enum_for(:
|
|
141
|
+
def each_section(&block)
|
|
142
|
+
return enum_for(:each_section) unless block_given?
|
|
124
143
|
|
|
125
144
|
Array.new(num_sections) do |i|
|
|
126
145
|
section_at(i).tap(&block)
|
|
127
146
|
end
|
|
128
147
|
end
|
|
129
148
|
|
|
149
|
+
# The name this used to go by, kept so that it keeps working.
|
|
150
|
+
alias each_sections each_section
|
|
151
|
+
|
|
130
152
|
# Simply use {#sections} to get all sections.
|
|
131
153
|
# @return [Array<ELFTools::Sections::Section>]
|
|
132
154
|
# Whole sections.
|
|
133
155
|
def sections
|
|
134
|
-
|
|
156
|
+
each_section.to_a
|
|
135
157
|
end
|
|
136
158
|
|
|
137
159
|
# Acquire the +n+-th section, 0-based.
|
|
@@ -160,17 +182,21 @@ module ELFTools
|
|
|
160
182
|
# elf.sections_by_type(:rela)
|
|
161
183
|
# #=> [#<ELFTools::Sections::RelocationSection:0x00563cd3219970>,
|
|
162
184
|
# # #<ELFTools::Sections::RelocationSection:0x00563cd3b89d70>]
|
|
163
|
-
def sections_by_type(type, &
|
|
185
|
+
def sections_by_type(type, &)
|
|
164
186
|
type = Util.to_constant(Constants::SHT, type)
|
|
165
|
-
Util.select_by_type(
|
|
187
|
+
Util.select_by_type(each_section, type, &)
|
|
166
188
|
end
|
|
167
189
|
|
|
168
|
-
#
|
|
190
|
+
# The section the names of the sections are recorded in, which the ELF
|
|
191
|
+
# header names by index.
|
|
169
192
|
#
|
|
170
|
-
#
|
|
171
|
-
#
|
|
172
|
-
# @return [ELFTools::Sections::StrTabSection] The
|
|
173
|
-
|
|
193
|
+
# It is not the section the names of the symbols are recorded in, which
|
|
194
|
+
# {ELFTools::Sections::SymTabSection#symstr} answers.
|
|
195
|
+
# @return [ELFTools::Sections::StrTabSection] The section.
|
|
196
|
+
# @example
|
|
197
|
+
# elf.section_name_table.name
|
|
198
|
+
# #=> '.shstrtab'
|
|
199
|
+
def section_name_table
|
|
174
200
|
section_at(header.e_shstrndx)
|
|
175
201
|
end
|
|
176
202
|
|
|
@@ -192,19 +218,22 @@ module ELFTools
|
|
|
192
218
|
# @yieldreturn [void]
|
|
193
219
|
# @return [Array<ELFTools::Segments::Segment>]
|
|
194
220
|
# Whole segments will be returned.
|
|
195
|
-
def
|
|
196
|
-
return enum_for(:
|
|
221
|
+
def each_segment(&block)
|
|
222
|
+
return enum_for(:each_segment) unless block_given?
|
|
197
223
|
|
|
198
224
|
Array.new(num_segments) do |i|
|
|
199
225
|
segment_at(i).tap(&block)
|
|
200
226
|
end
|
|
201
227
|
end
|
|
202
228
|
|
|
229
|
+
# The name this used to go by, kept so that it keeps working.
|
|
230
|
+
alias each_segments each_segment
|
|
231
|
+
|
|
203
232
|
# Simply use {#segments} to get all segments.
|
|
204
233
|
# @return [Array<ELFTools::Segments::Segment>]
|
|
205
234
|
# Whole segments.
|
|
206
235
|
def segments
|
|
207
|
-
|
|
236
|
+
each_segment.to_a
|
|
208
237
|
end
|
|
209
238
|
|
|
210
239
|
# Get the first segment with +p_type=type+.
|
|
@@ -250,7 +279,7 @@ module ELFTools
|
|
|
250
279
|
# #=> nil # no such segment exists
|
|
251
280
|
def segment_by_type(type)
|
|
252
281
|
type = Util.to_constant(Constants::PT, type)
|
|
253
|
-
|
|
282
|
+
each_segment.find { |seg| seg.header.p_type == type }
|
|
254
283
|
end
|
|
255
284
|
|
|
256
285
|
# Fetch all segments with specific type.
|
|
@@ -263,9 +292,9 @@ module ELFTools
|
|
|
263
292
|
# @yieldparam [ELFTools::Segments::Segment] segment A segment in specific type.
|
|
264
293
|
# @yieldreturn [void]
|
|
265
294
|
# @return [Array<ELFTools::Segments::Segment>] The target segments.
|
|
266
|
-
def segments_by_type(type, &
|
|
295
|
+
def segments_by_type(type, &)
|
|
267
296
|
type = Util.to_constant(Constants::PT, type)
|
|
268
|
-
Util.select_by_type(
|
|
297
|
+
Util.select_by_type(each_segment, type, &)
|
|
269
298
|
end
|
|
270
299
|
|
|
271
300
|
# Acquire the +n+-th segment, 0-based.
|
|
@@ -285,7 +314,7 @@ module ELFTools
|
|
|
285
314
|
# This method should work no matter ELF is a PIE or not.
|
|
286
315
|
# This method refers from (actually equals to) binutils/readelf.c#offset_from_vma.
|
|
287
316
|
# @param [Integer] vma The virtual address to be queried.
|
|
288
|
-
# @return [Integer] Related file offset.
|
|
317
|
+
# @return [Integer?] Related file offset. +nil+ if the queried region has no content in file.
|
|
289
318
|
# @example
|
|
290
319
|
# elf = ELFTools::ELFFile.new(File.open('/bin/cat'))
|
|
291
320
|
# elf.offset_from_vma(0x401337)
|
|
@@ -294,6 +323,25 @@ module ELFTools
|
|
|
294
323
|
segments_by_type(:load) do |seg|
|
|
295
324
|
return seg.vma_to_offset(vma) if seg.vma_in?(vma, size)
|
|
296
325
|
end
|
|
326
|
+
|
|
327
|
+
nil
|
|
328
|
+
end
|
|
329
|
+
|
|
330
|
+
# Get virtual address given offset in file
|
|
331
|
+
#
|
|
332
|
+
# @param [Integer] offset The file offset to be queried.
|
|
333
|
+
# @return [Integer?] Related virtual address. Note this is raw address, not always adjusted for base address.
|
|
334
|
+
# +nil+ if offset is invalid.
|
|
335
|
+
# @example
|
|
336
|
+
# elf = ELFTools::ELFFile.new(File.open('/bin/cat'))
|
|
337
|
+
# elf.vma_from_offset(0x1337)
|
|
338
|
+
# #=> 0x401337
|
|
339
|
+
def vma_from_offset(offset, size = 1)
|
|
340
|
+
segments_by_type(:load) do |seg|
|
|
341
|
+
return seg.offset_to_vma(offset) if seg.offset_in?(offset, size)
|
|
342
|
+
end
|
|
343
|
+
|
|
344
|
+
nil
|
|
297
345
|
end
|
|
298
346
|
|
|
299
347
|
# The patch status.
|
|
@@ -363,15 +411,18 @@ module ELFTools
|
|
|
363
411
|
shdr.read(stream)
|
|
364
412
|
Sections::Section.create(shdr, stream,
|
|
365
413
|
offset_from_vma: method(:offset_from_vma),
|
|
366
|
-
|
|
367
|
-
section_at: method(:section_at)
|
|
414
|
+
section_name_table: method(:section_name_table),
|
|
415
|
+
section_at: method(:section_at),
|
|
416
|
+
machine: header.e_machine.to_i)
|
|
368
417
|
end
|
|
369
418
|
|
|
370
419
|
def create_segment(n)
|
|
371
420
|
stream.pos = header.e_phoff + n * header.e_phentsize
|
|
372
421
|
phdr = Structs::ELF_Phdr[elf_class].new(endian:, offset: stream.pos)
|
|
373
422
|
phdr.elf_class = elf_class
|
|
374
|
-
Segments::Segment.create(phdr.read(stream), stream,
|
|
423
|
+
Segments::Segment.create(phdr.read(stream), stream,
|
|
424
|
+
offset_from_vma: method(:offset_from_vma),
|
|
425
|
+
machine: header.e_machine.to_i)
|
|
375
426
|
end
|
|
376
427
|
end
|
|
377
428
|
end
|
data/lib/elftools/lazy_array.rb
CHANGED
|
@@ -7,6 +7,9 @@ module ELFTools
|
|
|
7
7
|
# 'lazy loading' objects.
|
|
8
8
|
# Mainly used when loading sections, segments, and
|
|
9
9
|
# symbols.
|
|
10
|
+
#
|
|
11
|
+
# Only {#[]} loads an element on demand, any other method
|
|
12
|
+
# of +Array+ loads all elements before it operates.
|
|
10
13
|
class LazyArray < SimpleDelegator
|
|
11
14
|
# Instantiate a {LazyArray} object.
|
|
12
15
|
# @param [Integer] size
|
|
@@ -28,7 +31,8 @@ module ELFTools
|
|
|
28
31
|
# p arr[3]
|
|
29
32
|
# # 9
|
|
30
33
|
def initialize(size, &block)
|
|
31
|
-
|
|
34
|
+
@array = Array.new(size)
|
|
35
|
+
super(@array)
|
|
32
36
|
@block = block
|
|
33
37
|
end
|
|
34
38
|
|
|
@@ -36,14 +40,48 @@ module ELFTools
|
|
|
36
40
|
#
|
|
37
41
|
# Elements are lazy loaded at the first time
|
|
38
42
|
# access it.
|
|
43
|
+
# @param [Integer] i
|
|
44
|
+
# The index, negative index is *not* supported.
|
|
39
45
|
# @return [Object]
|
|
40
46
|
# The element, returned type is the
|
|
41
47
|
# return type of block given in {#initialize}.
|
|
48
|
+
# +nil+ if +i+ is out of bound.
|
|
42
49
|
def [](i)
|
|
43
|
-
|
|
44
|
-
return nil unless i.between?(0, __getobj__.size - 1)
|
|
50
|
+
return nil unless i.between?(0, size - 1)
|
|
45
51
|
|
|
46
|
-
|
|
52
|
+
@array[i] ||= @block.call(i)
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
# The size of this array.
|
|
56
|
+
#
|
|
57
|
+
# This method never loads any element.
|
|
58
|
+
# @return [Integer]
|
|
59
|
+
# The size given in {#initialize}.
|
|
60
|
+
def size
|
|
61
|
+
@array.size
|
|
62
|
+
end
|
|
63
|
+
alias length size
|
|
64
|
+
|
|
65
|
+
# Loads all elements.
|
|
66
|
+
#
|
|
67
|
+
# Called whenever a method other than {#[]} and {#size} is invoked, so that
|
|
68
|
+
# those methods operate on a fully loaded array.
|
|
69
|
+
# @return [Array]
|
|
70
|
+
# The loaded array.
|
|
71
|
+
# @example
|
|
72
|
+
# arr = LazyArray.new(3) { |i| i * i }
|
|
73
|
+
# p arr.map { |v| v + 1 }
|
|
74
|
+
# # [1, 2, 5]
|
|
75
|
+
def __getobj__
|
|
76
|
+
@array.each_index { |i| self[i] }
|
|
77
|
+
@array
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
private
|
|
81
|
+
|
|
82
|
+
# Queries the array without loading any element.
|
|
83
|
+
def respond_to_missing?(name, include_private = false)
|
|
84
|
+
@array.respond_to?(name, include_private)
|
|
47
85
|
end
|
|
48
86
|
end
|
|
49
87
|
end
|
data/lib/elftools/note.rb
CHANGED
|
@@ -41,8 +41,8 @@ module ELFTools
|
|
|
41
41
|
# @return [Enumerator<ELFTools::Note::Note>, Array<ELFTools::Note::Note>]
|
|
42
42
|
# If block is not given, an enumerator will be returned.
|
|
43
43
|
# Otherwise, return the array of notes.
|
|
44
|
-
def
|
|
45
|
-
return enum_for(:
|
|
44
|
+
def each_note
|
|
45
|
+
return enum_for(:each_note) unless block_given?
|
|
46
46
|
|
|
47
47
|
@notes_offset_map ||= {}
|
|
48
48
|
cur = note_start
|
|
@@ -61,11 +61,14 @@ module ELFTools
|
|
|
61
61
|
notes
|
|
62
62
|
end
|
|
63
63
|
|
|
64
|
+
# The name this used to go by, kept so that it keeps working.
|
|
65
|
+
alias each_notes each_note
|
|
66
|
+
|
|
64
67
|
# Simply +#notes+ to get all notes.
|
|
65
68
|
# @return [Array<ELFTools::Note::Note>]
|
|
66
69
|
# Whole notes.
|
|
67
70
|
def notes
|
|
68
|
-
|
|
71
|
+
each_note.to_a
|
|
69
72
|
end
|
|
70
73
|
|
|
71
74
|
private
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'elftools/constants'
|
|
4
|
+
|
|
5
|
+
module ELFTools
|
|
6
|
+
# A relocation entry.
|
|
7
|
+
#
|
|
8
|
+
# Can be either a REL or RELA relocation.
|
|
9
|
+
class Relocation
|
|
10
|
+
attr_reader :header # @return [ELFTools::Structs::ELF_Rel, ELFTools::Structs::ELF_Rela] Rel(a) header.
|
|
11
|
+
attr_reader :stream # @return [#pos=, #read] Streaming object.
|
|
12
|
+
|
|
13
|
+
# Instantiate a {Relocation} object.
|
|
14
|
+
# @param [ELFTools::Structs::ELF_Rel, ELFTools::Structs::ELF_Rela] header
|
|
15
|
+
# The relocation header.
|
|
16
|
+
# @param [#pos=, #read] stream The streaming object.
|
|
17
|
+
# @param [Integer] machine
|
|
18
|
+
# The machine of the ELF file, which decides what {#type} means and how
|
|
19
|
+
# {#header} records it.
|
|
20
|
+
def initialize(header, stream, machine: nil)
|
|
21
|
+
@header = header
|
|
22
|
+
@stream = stream
|
|
23
|
+
@machine = machine
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# Which symbol this relocation is against, as an index into the symbol
|
|
27
|
+
# table.
|
|
28
|
+
# @return [Integer] The symbol index.
|
|
29
|
+
def symbol_index
|
|
30
|
+
sym_and_type.first
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# What this relocation does, which only means something together with the
|
|
34
|
+
# machine of the file. {#type_name} names it.
|
|
35
|
+
# @return [Integer] The relocation type.
|
|
36
|
+
def type
|
|
37
|
+
sym_and_type.last
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# The name of {#type}.
|
|
41
|
+
#
|
|
42
|
+
# Every architecture numbers relocation types on its own, so the name is
|
|
43
|
+
# only known when the machine of the file is.
|
|
44
|
+
# @return [String] The name.
|
|
45
|
+
# @example
|
|
46
|
+
# relocation.type_name
|
|
47
|
+
# #=> 'R_X86_64_JUMP_SLOT'
|
|
48
|
+
def type_name
|
|
49
|
+
Constants::R.mapping(@machine, type)
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
private
|
|
53
|
+
|
|
54
|
+
# What +r_info+ records, i.e. a symbol index and a relocation type. Most
|
|
55
|
+
# machines split the field in half between the two, one lays it out its
|
|
56
|
+
# own way.
|
|
57
|
+
# @return [Array(Integer, Integer)] The symbol index and the type.
|
|
58
|
+
def sym_and_type
|
|
59
|
+
return mips64_sym_and_type if mips64?
|
|
60
|
+
|
|
61
|
+
[header.r_info >> mask_bit, header.r_info & ((1 << mask_bit) - 1)]
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
# Whether the file records relocations the way the 64-bit MIPS ABI does,
|
|
65
|
+
# which is the one layout that departs from halving +r_info+.
|
|
66
|
+
# @return [Boolean] The answer.
|
|
67
|
+
def mips64?
|
|
68
|
+
@machine == Constants::EM_MIPS && header.elf_class == 64
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
# Reads +r_info+ as the 64-bit MIPS ABI records it, i.e. a symbol index of
|
|
72
|
+
# four bytes followed by four bytes the ABI keeps for itself, the last of
|
|
73
|
+
# which is the type reported here. Those bytes are ordered as the rest of
|
|
74
|
+
# the file is, which is why the two ends of the field swap places.
|
|
75
|
+
# @example
|
|
76
|
+
# # A big endian file records the symbol index first,
|
|
77
|
+
# # 00 00 00 08 | 00 05 18 07
|
|
78
|
+
# # sym | ssym type3 type2 type
|
|
79
|
+
# 0x0000000800051807 #=> [8, 7]
|
|
80
|
+
# # a little endian one records the very same relocation as
|
|
81
|
+
# 0x0718050000000008 #=> [8, 7]
|
|
82
|
+
# @return [Array(Integer, Integer)] The symbol index and the type.
|
|
83
|
+
def mips64_sym_and_type
|
|
84
|
+
info = header.r_info.to_i
|
|
85
|
+
return [info >> 32, info & 0xff] if header.class.self_endian == :big
|
|
86
|
+
|
|
87
|
+
[info & 0xffff_ffff, info >> 56]
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def mask_bit
|
|
91
|
+
header.elf_class == 32 ? 8 : 32
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
end
|
|
@@ -12,6 +12,19 @@ module ELFTools
|
|
|
12
12
|
class DynamicSection < Section
|
|
13
13
|
include ELFTools::Dynamic
|
|
14
14
|
|
|
15
|
+
# Instantiate a {DynamicSection} object.
|
|
16
|
+
# @param [ELFTools::Structs::ELF_Shdr] header
|
|
17
|
+
# See {Section#initialize} for more information.
|
|
18
|
+
# @param [#pos=, #read] stream
|
|
19
|
+
# See {Section#initialize} for more information.
|
|
20
|
+
# @param [Integer] machine
|
|
21
|
+
# The machine of the ELF file, which decides what the entries a tag
|
|
22
|
+
# points at mean. This should be +e_machine+ of the ELF header.
|
|
23
|
+
def initialize(header, stream, machine: nil, **_kwargs)
|
|
24
|
+
@machine = machine
|
|
25
|
+
super
|
|
26
|
+
end
|
|
27
|
+
|
|
15
28
|
# Get the start address of tags.
|
|
16
29
|
# @return [Integer] Start address of tags.
|
|
17
30
|
def tag_start
|
|
@@ -1,14 +1,29 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require 'elftools/constants'
|
|
4
|
+
require 'elftools/relocation'
|
|
4
5
|
require 'elftools/sections/section'
|
|
5
6
|
require 'elftools/structs'
|
|
6
7
|
|
|
7
8
|
module ELFTools
|
|
8
9
|
module Sections
|
|
9
|
-
# Class of
|
|
10
|
-
#
|
|
10
|
+
# Class of relocation section.
|
|
11
|
+
# Usually for sections .rel.* and .rela.*,
|
|
12
|
+
# which record relocations in ELF file.
|
|
11
13
|
class RelocationSection < Section
|
|
14
|
+
# Instantiate a {RelocationSection} object.
|
|
15
|
+
# @param [ELFTools::Structs::ELF_Shdr] header
|
|
16
|
+
# See {Section#initialize} for more information.
|
|
17
|
+
# @param [#pos=, #read] stream
|
|
18
|
+
# See {Section#initialize} for more information.
|
|
19
|
+
# @param [Integer] machine
|
|
20
|
+
# The machine of the ELF file, which decides what a relocation type
|
|
21
|
+
# means. This should be +e_machine+ of the ELF header.
|
|
22
|
+
def initialize(header, stream, machine: nil, **_kwargs)
|
|
23
|
+
@machine = machine
|
|
24
|
+
super
|
|
25
|
+
end
|
|
26
|
+
|
|
12
27
|
# Is this relocation a RELA or REL type.
|
|
13
28
|
# @return [Boolean] If is RELA.
|
|
14
29
|
def rela?
|
|
@@ -42,19 +57,22 @@ module ELFTools
|
|
|
42
57
|
# @return [Enumerator<ELFTools::Relocation>, Array<ELFTools::Relocation>]
|
|
43
58
|
# If block is not given, an enumerator will be returned.
|
|
44
59
|
# Otherwise, the whole relocations will be returned.
|
|
45
|
-
def
|
|
46
|
-
return enum_for(:
|
|
60
|
+
def each_relocation(&block)
|
|
61
|
+
return enum_for(:each_relocation) unless block_given?
|
|
47
62
|
|
|
48
63
|
Array.new(num_relocations) do |i|
|
|
49
64
|
relocation_at(i).tap(&block)
|
|
50
65
|
end
|
|
51
66
|
end
|
|
52
67
|
|
|
68
|
+
# The name this used to go by, kept so that it keeps working.
|
|
69
|
+
alias each_relocations each_relocation
|
|
70
|
+
|
|
53
71
|
# Simply use {#relocations} to get all relocations.
|
|
54
72
|
# @return [Array<ELFTools::Relocation>]
|
|
55
73
|
# Whole relocations.
|
|
56
74
|
def relocations
|
|
57
|
-
|
|
75
|
+
each_relocation.to_a
|
|
58
76
|
end
|
|
59
77
|
|
|
60
78
|
private
|
|
@@ -65,45 +83,8 @@ module ELFTools
|
|
|
65
83
|
rel = klass.new(endian: header.class.self_endian, offset: stream.pos)
|
|
66
84
|
rel.elf_class = header.elf_class
|
|
67
85
|
rel.read(stream)
|
|
68
|
-
Relocation.new(rel, stream)
|
|
86
|
+
Relocation.new(rel, stream, machine: @machine)
|
|
69
87
|
end
|
|
70
88
|
end
|
|
71
89
|
end
|
|
72
|
-
|
|
73
|
-
# A relocation entry.
|
|
74
|
-
#
|
|
75
|
-
# Can be either a REL or RELA relocation.
|
|
76
|
-
# XXX: move this to an independent file?
|
|
77
|
-
class Relocation
|
|
78
|
-
attr_reader :header # @return [ELFTools::Structs::ELF_Rel, ELFTools::Structs::ELF_Rela] Rel(a) header.
|
|
79
|
-
attr_reader :stream # @return [#pos=, #read] Streaming object.
|
|
80
|
-
|
|
81
|
-
# Instantiate a {Relocation} object.
|
|
82
|
-
def initialize(header, stream)
|
|
83
|
-
@header = header
|
|
84
|
-
@stream = stream
|
|
85
|
-
end
|
|
86
|
-
|
|
87
|
-
# +r_info+ contains sym and type, use two methods
|
|
88
|
-
# to access them easier.
|
|
89
|
-
# @return [Integer] sym infor.
|
|
90
|
-
def r_info_sym
|
|
91
|
-
header.r_info >> mask_bit
|
|
92
|
-
end
|
|
93
|
-
alias symbol_index r_info_sym
|
|
94
|
-
|
|
95
|
-
# +r_info+ contains sym and type, use two methods
|
|
96
|
-
# to access them easier.
|
|
97
|
-
# @return [Integer] type infor.
|
|
98
|
-
def r_info_type
|
|
99
|
-
header.r_info & ((1 << mask_bit) - 1)
|
|
100
|
-
end
|
|
101
|
-
alias type r_info_type
|
|
102
|
-
|
|
103
|
-
private
|
|
104
|
-
|
|
105
|
-
def mask_bit
|
|
106
|
-
header.elf_class == 32 ? 8 : 32
|
|
107
|
-
end
|
|
108
|
-
end
|
|
109
90
|
end
|
|
@@ -13,16 +13,16 @@ module ELFTools
|
|
|
13
13
|
# The section header object.
|
|
14
14
|
# @param [#pos=, #read] stream
|
|
15
15
|
# The streaming object for further dump.
|
|
16
|
-
# @param [ELFTools::Sections::StrTabSection, Proc]
|
|
16
|
+
# @param [ELFTools::Sections::StrTabSection, Proc] section_name_table
|
|
17
17
|
# The string table object. For fetching section names.
|
|
18
18
|
# If +Proc+ if given, it will call at the first
|
|
19
19
|
# time access +#name+.
|
|
20
20
|
# @param [Method] offset_from_vma
|
|
21
21
|
# The method to get offset of file, given virtual memory address.
|
|
22
|
-
def initialize(header, stream, offset_from_vma: nil,
|
|
22
|
+
def initialize(header, stream, offset_from_vma: nil, section_name_table: nil, **_kwargs)
|
|
23
23
|
@header = header
|
|
24
24
|
@stream = stream
|
|
25
|
-
@
|
|
25
|
+
@section_name_table = section_name_table
|
|
26
26
|
@offset_from_vma = offset_from_vma
|
|
27
27
|
end
|
|
28
28
|
|
|
@@ -36,7 +36,7 @@ module ELFTools
|
|
|
36
36
|
# Get name of this section.
|
|
37
37
|
# @return [String] The name.
|
|
38
38
|
def name
|
|
39
|
-
@name ||= @
|
|
39
|
+
@name ||= @section_name_table.call.name_at(header.sh_name)
|
|
40
40
|
end
|
|
41
41
|
|
|
42
42
|
# Fetch data of this section.
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require 'elftools/sections/section'
|
|
4
|
+
require 'elftools/sections/symbol'
|
|
4
5
|
|
|
5
6
|
module ELFTools
|
|
6
7
|
module Sections
|
|
@@ -18,8 +19,12 @@ module ELFTools
|
|
|
18
19
|
# @param [Proc] section_at
|
|
19
20
|
# The method for fetching other sections by index.
|
|
20
21
|
# This lambda should be {ELFTools::ELFFile#section_at}.
|
|
21
|
-
|
|
22
|
+
# @param [Integer] machine
|
|
23
|
+
# The machine of the ELF file, which decides what the fields of a
|
|
24
|
+
# symbol mean. This should be +e_machine+ of the ELF header.
|
|
25
|
+
def initialize(header, stream, section_at: nil, machine: nil, **_kwargs)
|
|
22
26
|
@section_at = section_at
|
|
27
|
+
@machine = machine
|
|
23
28
|
# For faster #symbol_by_name
|
|
24
29
|
super
|
|
25
30
|
end
|
|
@@ -56,19 +61,22 @@ module ELFTools
|
|
|
56
61
|
# @return [Enumerator<ELFTools::Sections::Symbol>, Array<ELFTools::Sections::Symbol>]
|
|
57
62
|
# If block is not given, an enumerator will be returned.
|
|
58
63
|
# Otherwise return array of symbols.
|
|
59
|
-
def
|
|
60
|
-
return enum_for(:
|
|
64
|
+
def each_symbol(&block)
|
|
65
|
+
return enum_for(:each_symbol) unless block_given?
|
|
61
66
|
|
|
62
67
|
Array.new(num_symbols) do |i|
|
|
63
68
|
symbol_at(i).tap(&block)
|
|
64
69
|
end
|
|
65
70
|
end
|
|
66
71
|
|
|
72
|
+
# The name this used to go by, kept so that it keeps working.
|
|
73
|
+
alias each_symbols each_symbol
|
|
74
|
+
|
|
67
75
|
# Simply use {#symbols} to get all symbols.
|
|
68
76
|
# @return [Array<ELFTools::Sections::Symbol>]
|
|
69
77
|
# The whole symbols.
|
|
70
78
|
def symbols
|
|
71
|
-
|
|
79
|
+
each_symbol.to_a
|
|
72
80
|
end
|
|
73
81
|
|
|
74
82
|
# Get symbol by its name.
|
|
@@ -76,7 +84,7 @@ module ELFTools
|
|
|
76
84
|
# The name of symbol.
|
|
77
85
|
# @return [ELFTools::Sections::Symbol] Desired symbol.
|
|
78
86
|
def symbol_by_name(name)
|
|
79
|
-
|
|
87
|
+
each_symbol.find { |symbol| symbol.name == name }
|
|
80
88
|
end
|
|
81
89
|
|
|
82
90
|
# Return the symbol string section.
|
|
@@ -92,35 +100,7 @@ module ELFTools
|
|
|
92
100
|
stream.pos = header.sh_offset + n * header.sh_entsize
|
|
93
101
|
sym = Structs::ELF_sym[header.elf_class].new(endian: header.class.self_endian, offset: stream.pos)
|
|
94
102
|
sym.read(stream)
|
|
95
|
-
Symbol.new(sym, stream, symstr: method(:symstr))
|
|
96
|
-
end
|
|
97
|
-
end
|
|
98
|
-
|
|
99
|
-
# Class of symbol.
|
|
100
|
-
#
|
|
101
|
-
# XXX: Should this class be defined in an independent file?
|
|
102
|
-
class Symbol
|
|
103
|
-
attr_reader :header # @return [ELFTools::Structs::ELF32_sym, ELFTools::Structs::ELF64_sym] Section header.
|
|
104
|
-
attr_reader :stream # @return [#pos=, #read] Streaming object.
|
|
105
|
-
|
|
106
|
-
# Instantiate a {ELFTools::Sections::Symbol} object.
|
|
107
|
-
# @param [ELFTools::Structs::ELF32_sym, ELFTools::Structs::ELF64_sym] header
|
|
108
|
-
# The symbol header.
|
|
109
|
-
# @param [#pos=, #read] stream The streaming object.
|
|
110
|
-
# @param [ELFTools::Sections::StrTabSection, Proc] symstr
|
|
111
|
-
# The symbol string section.
|
|
112
|
-
# If +Proc+ is given, it will be called at the first time
|
|
113
|
-
# access {Symbol#name}.
|
|
114
|
-
def initialize(header, stream, symstr: nil)
|
|
115
|
-
@header = header
|
|
116
|
-
@stream = stream
|
|
117
|
-
@symstr = symstr
|
|
118
|
-
end
|
|
119
|
-
|
|
120
|
-
# Return the symbol name.
|
|
121
|
-
# @return [String] The name.
|
|
122
|
-
def name
|
|
123
|
-
@name ||= @symstr.call.name_at(header.st_name)
|
|
103
|
+
Symbol.new(sym, stream, symstr: method(:symstr), machine: @machine)
|
|
124
104
|
end
|
|
125
105
|
end
|
|
126
106
|
end
|