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.
Files changed (104) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +111 -7
  3. data/lib/elftools/constants/machine.rb +248 -0
  4. data/lib/elftools/constants/machine_names.rb +246 -0
  5. data/lib/elftools/constants/relocation/aarch64.rb +213 -0
  6. data/lib/elftools/constants/relocation/alpha.rb +47 -0
  7. data/lib/elftools/constants/relocation/amdgpu.rb +28 -0
  8. data/lib/elftools/constants/relocation/arm.rb +150 -0
  9. data/lib/elftools/constants/relocation/avr.rb +51 -0
  10. data/lib/elftools/constants/relocation/bfin.rb +72 -0
  11. data/lib/elftools/constants/relocation/bpf.rb +21 -0
  12. data/lib/elftools/constants/relocation/cr16.rb +46 -0
  13. data/lib/elftools/constants/relocation/cris.rb +46 -0
  14. data/lib/elftools/constants/relocation/crx.rb +35 -0
  15. data/lib/elftools/constants/relocation/csky.rb +79 -0
  16. data/lib/elftools/constants/relocation/d10v.rb +23 -0
  17. data/lib/elftools/constants/relocation/d30v.rb +27 -0
  18. data/lib/elftools/constants/relocation/dlx.rb +24 -0
  19. data/lib/elftools/constants/relocation/epiphany.rb +28 -0
  20. data/lib/elftools/constants/relocation/fr30.rb +27 -0
  21. data/lib/elftools/constants/relocation/frv.rb +57 -0
  22. data/lib/elftools/constants/relocation/ft32.rb +27 -0
  23. data/lib/elftools/constants/relocation/h8.rb +69 -0
  24. data/lib/elftools/constants/relocation/hppa.rb +135 -0
  25. data/lib/elftools/constants/relocation/i370.rb +26 -0
  26. data/lib/elftools/constants/relocation/i386.rb +59 -0
  27. data/lib/elftools/constants/relocation/i860.rb +48 -0
  28. data/lib/elftools/constants/relocation/i960.rb +22 -0
  29. data/lib/elftools/constants/relocation/ia64.rb +117 -0
  30. data/lib/elftools/constants/relocation/ip2k.rb +29 -0
  31. data/lib/elftools/constants/relocation/iq2000.rb +27 -0
  32. data/lib/elftools/constants/relocation/kvx.rb +97 -0
  33. data/lib/elftools/constants/relocation/lm32.rb +32 -0
  34. data/lib/elftools/constants/relocation/loongarch.rb +144 -0
  35. data/lib/elftools/constants/relocation/m32c.rb +27 -0
  36. data/lib/elftools/constants/relocation/m32r.rb +57 -0
  37. data/lib/elftools/constants/relocation/m68hc11.rb +35 -0
  38. data/lib/elftools/constants/relocation/m68k.rb +57 -0
  39. data/lib/elftools/constants/relocation/mcore.rb +27 -0
  40. data/lib/elftools/constants/relocation/mep.rb +36 -0
  41. data/lib/elftools/constants/relocation/metag.rb +63 -0
  42. data/lib/elftools/constants/relocation/microblaze.rb +48 -0
  43. data/lib/elftools/constants/relocation/mips.rb +125 -0
  44. data/lib/elftools/constants/relocation/mmix.rb +51 -0
  45. data/lib/elftools/constants/relocation/mn10200.rb +22 -0
  46. data/lib/elftools/constants/relocation/mn10300.rb +49 -0
  47. data/lib/elftools/constants/relocation/moxie.rb +17 -0
  48. data/lib/elftools/constants/relocation/msp430.rb +27 -0
  49. data/lib/elftools/constants/relocation/msp430x.rb +37 -0
  50. data/lib/elftools/constants/relocation/mt.rb +21 -0
  51. data/lib/elftools/constants/relocation/nds32.rb +167 -0
  52. data/lib/elftools/constants/relocation/nfp.rb +41 -0
  53. data/lib/elftools/constants/relocation/nfp3200.rb +46 -0
  54. data/lib/elftools/constants/relocation/nios2.rb +74 -0
  55. data/lib/elftools/constants/relocation/or1k.rb +69 -0
  56. data/lib/elftools/constants/relocation/pj.rb +24 -0
  57. data/lib/elftools/constants/relocation/ppc.rb +131 -0
  58. data/lib/elftools/constants/relocation/ppc64.rb +177 -0
  59. data/lib/elftools/constants/relocation/pru.rb +31 -0
  60. data/lib/elftools/constants/relocation/riscv.rb +74 -0
  61. data/lib/elftools/constants/relocation/rl78.rb +70 -0
  62. data/lib/elftools/constants/relocation/rx.rb +81 -0
  63. data/lib/elftools/constants/relocation/s12z.rb +22 -0
  64. data/lib/elftools/constants/relocation/s390.rb +82 -0
  65. data/lib/elftools/constants/relocation/score.rb +36 -0
  66. data/lib/elftools/constants/relocation/sh.rb +124 -0
  67. data/lib/elftools/constants/relocation/sparc.rb +108 -0
  68. data/lib/elftools/constants/relocation/spu.rb +32 -0
  69. data/lib/elftools/constants/relocation/tic6x.rb +48 -0
  70. data/lib/elftools/constants/relocation/tilegx.rb +134 -0
  71. data/lib/elftools/constants/relocation/tilepro.rb +105 -0
  72. data/lib/elftools/constants/relocation/v800.rb +101 -0
  73. data/lib/elftools/constants/relocation/v850.rb +66 -0
  74. data/lib/elftools/constants/relocation/vax.rb +29 -0
  75. data/lib/elftools/constants/relocation/visium.rb +30 -0
  76. data/lib/elftools/constants/relocation/wasm32.rb +16 -0
  77. data/lib/elftools/constants/relocation/x86_64.rb +68 -0
  78. data/lib/elftools/constants/relocation/xgate.rb +34 -0
  79. data/lib/elftools/constants/relocation/xstormy16.rb +29 -0
  80. data/lib/elftools/constants/relocation/xtensa.rb +75 -0
  81. data/lib/elftools/constants/relocation/z80.rb +28 -0
  82. data/lib/elftools/constants/relocation.rb +181 -0
  83. data/lib/elftools/constants.rb +124 -231
  84. data/lib/elftools/dynamic/hash_table.rb +216 -0
  85. data/lib/elftools/dynamic/string_table.rb +30 -0
  86. data/lib/elftools/dynamic/symbols.rb +146 -0
  87. data/lib/elftools/dynamic/tag.rb +66 -0
  88. data/lib/elftools/dynamic.rb +102 -62
  89. data/lib/elftools/elf_file.rb +73 -22
  90. data/lib/elftools/lazy_array.rb +42 -4
  91. data/lib/elftools/note.rb +6 -3
  92. data/lib/elftools/relocation.rb +94 -0
  93. data/lib/elftools/sections/dynamic_section.rb +13 -0
  94. data/lib/elftools/sections/relocation_section.rb +24 -43
  95. data/lib/elftools/sections/section.rb +4 -4
  96. data/lib/elftools/sections/sym_tab_section.rb +14 -34
  97. data/lib/elftools/sections/symbol.rb +112 -0
  98. data/lib/elftools/segments/dynamic_segment.rb +1 -0
  99. data/lib/elftools/segments/load_segment.rb +33 -5
  100. data/lib/elftools/segments/segment.rb +8 -4
  101. data/lib/elftools/structs.rb +24 -3
  102. data/lib/elftools/util.rb +1 -1
  103. data/lib/elftools/version.rb +1 -1
  104. metadata +101 -11
@@ -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
- each_sections.find { |sec| sec.name == name }
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 each_sections(&block)
123
- return enum_for(:each_sections) unless block_given?
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
- each_sections.to_a
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, &block)
185
+ def sections_by_type(type, &)
164
186
  type = Util.to_constant(Constants::SHT, type)
165
- Util.select_by_type(each_sections, type, &block)
187
+ Util.select_by_type(each_section, type, &)
166
188
  end
167
189
 
168
- # Get the string table section.
190
+ # The section the names of the sections are recorded in, which the ELF
191
+ # header names by index.
169
192
  #
170
- # This section is acquired by using the +e_shstrndx+
171
- # in ELF header.
172
- # @return [ELFTools::Sections::StrTabSection] The desired section.
173
- def strtab_section
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 each_segments(&block)
196
- return enum_for(:each_segments) unless block_given?
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
- each_segments.to_a
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
- each_segments.find { |seg| seg.header.p_type == type }
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, &block)
295
+ def segments_by_type(type, &)
267
296
  type = Util.to_constant(Constants::PT, type)
268
- Util.select_by_type(each_segments, type, &block)
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
- strtab: method(:strtab_section),
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, offset_from_vma: method(:offset_from_vma))
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
@@ -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
- super(Array.new(size))
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
- # XXX: support negative index?
44
- return nil unless i.between?(0, __getobj__.size - 1)
50
+ return nil unless i.between?(0, size - 1)
45
51
 
46
- __getobj__[i] ||= @block.call(i)
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 each_notes
45
- return enum_for(:each_notes) unless block_given?
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
- each_notes.to_a
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 note section.
10
- # Note section records notes
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 each_relocations(&block)
46
- return enum_for(:each_relocations) unless block_given?
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
- each_relocations.to_a
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] strtab
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, strtab: nil, **_kwargs)
22
+ def initialize(header, stream, offset_from_vma: nil, section_name_table: nil, **_kwargs)
23
23
  @header = header
24
24
  @stream = stream
25
- @strtab = strtab
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 ||= @strtab.call.name_at(header.sh_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
- def initialize(header, stream, section_at: nil, **_kwargs)
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 each_symbols(&block)
60
- return enum_for(:each_symbols) unless block_given?
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
- each_symbols.to_a
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
- each_symbols.find { |symbol| symbol.name == name }
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