elftools 0.1.0 → 0.2.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: c59b0333aab08b885d294a4d0295d6bac48eb11c
4
- data.tar.gz: 79ce95770fcf3911db8c7260bc6009d8e3cf2839
3
+ metadata.gz: b2aa2517a78c13a631e9889e03e380b024c75585
4
+ data.tar.gz: 6d1de34194028eba0b787b148b648a518e6f0e1d
5
5
  SHA512:
6
- metadata.gz: f1bf67e49c1d910509199fd1c4276760ecc022a9e88a1045ddd3aeccab62f258a176bc57b059b71eec3b74bde3d652d666b53284a701785df5c79a385dbfc8aa
7
- data.tar.gz: e5b41464b5b6d092bbb0cf752b73594a8771d5c91840ee471fd0744ed7259d994c25a3a46d2e2d509907aef12b1e0c817a77b1d544f3c5bd01c350e2f3b4cd0a
6
+ metadata.gz: 4e3b9b1c4f4e0c7cf38efd85ae0c5c250e875fb50bda990286fcf0dc69684970b6eae99f6b2881a0938ea5597da6439ae46fa694823dc3e69322e202b60f622b
7
+ data.tar.gz: fff51965be7467711d36af1db1374370654a7d8a771ca8f4dcc48e38fd3daff3fe928dc2dd034f3d7ded3ecadb4e8304bdc8feb996623fc052c6eeea03251742
data/README.md CHANGED
@@ -98,6 +98,21 @@ elf.segment_by_type(:interp).interp_name
98
98
  #=> "/lib64/ld-linux-x86-64.so.2"
99
99
  ```
100
100
 
101
+ ## Relocations
102
+ ```ruby
103
+ elf = ELFTools::ELFFile.new(File.open('spec/files/amd64.elf'))
104
+ # Use relocation to get plt names.
105
+ rela_section = elf.sections_by_type(:rela).last
106
+ rela_section.name
107
+ #=> ".rela.plt"
108
+ relocations = rela_section.relocations
109
+ relocations.map { |r| '%x' % r.header.r_info }
110
+ #=> ["100000007", "200000007", "300000007", "400000007", "500000007", "700000007"]
111
+ symtab = elf.section_at(rela_section.header.sh_link) # get the symbol table section
112
+ relocations.map { |r| symtab.symbol_at(r.symbol_index).name }
113
+ #=> ["puts", "__stack_chk_fail", "printf", "__libc_start_main", "fgets", "scanf"]
114
+ ```
115
+
101
116
  # Why rbelftools
102
117
 
103
118
  1. Fully documented
@@ -117,7 +132,7 @@ elf.segment_by_type(:interp).interp_name
117
132
  **rbelftools** is designed to be a library for furthur usage.
118
133
  It will _not_ add any too trivial features.
119
134
  For example, to check if NX disabled, you can use
120
- `elf.segment_by_type(:gnu_stack).executable?` but not `elf.nx?`
135
+ `!elf.segment_by_type(:gnu_stack).executable?` but not `elf.nx?`
121
136
  5. Section and segment parser
122
137
 
123
138
  Providing common sections and segments parser. For example, .symtab, .shstrtab
@@ -1,6 +1,7 @@
1
1
  module ELFTools
2
2
  # Define constants from elf.h.
3
- # Mostly refer from https://github.com/torvalds/linux/blob/master/include/uapi/linux/elf.h.
3
+ # Mostly refer from https://github.com/torvalds/linux/blob/master/include/uapi/linux/elf.h
4
+ # and binutils/elfcpp/elfcpp.h.
4
5
  module Constants
5
6
  # ELF magic header
6
7
  ELFMAG = "\x7FELF".freeze
@@ -42,53 +43,61 @@ module ELFTools
42
43
  PT_LOPROC = 0x70000000
43
44
  PT_HIPROC = 0x7fffffff
44
45
  PT_GNU_EH_FRAME = 0x6474e550
45
- PT_GNU_STACK = (PT_LOOS + 0x474e551)
46
+ PT_GNU_STACK = 0x6474e551
47
+ PT_GNU_RELRO = 0x6474e552 # Read only after relocation
46
48
  end
47
49
  include PT
48
50
 
49
51
  # Dynamic table types, records in +d_tag+.
50
52
  module DT
51
- DT_NULL = 0
52
- DT_NEEDED = 1
53
- DT_PLTRELSZ = 2
54
- DT_PLTGOT = 3
55
- DT_HASH = 4
56
- DT_STRTAB = 5
57
- DT_SYMTAB = 6
58
- DT_RELA = 7
59
- DT_RELASZ = 8
60
- DT_RELAENT = 9
61
- DT_STRSZ = 10
62
- DT_SYMENT = 11
63
- DT_INIT = 12
64
- DT_FINI = 13
65
- DT_SONAME = 14
66
- DT_RPATH = 15
67
- DT_SYMBOLIC = 16
68
- DT_REL = 17
69
- DT_RELSZ = 18
70
- DT_RELENT = 19
71
- DT_PLTREL = 20
72
- DT_DEBUG = 21
73
- DT_TEXTREL = 22
74
- DT_JMPREL = 23
75
- DT_ENCODING = 32
76
- DT_LOOS = 0x6000000d
77
- DT_HIOS = 0x6ffff000
78
- DT_VALRNGLO = 0x6ffffd00
79
- DT_VALRNGHI = 0x6ffffdff
80
- DT_ADDRRNGLO = 0x6ffffe00
81
- DT_ADDRRNGHI = 0x6ffffeff
82
- DT_VERSYM = 0x6ffffff0
83
- DT_RELACOUNT = 0x6ffffff9
84
- DT_RELCOUNT = 0x6ffffffa
85
- DT_FLAGS_1 = 0x6ffffffb
86
- DT_VERDEF = 0x6ffffffc
87
- DT_VERDEFNUM = 0x6ffffffd
88
- DT_VERNEED = 0x6ffffffe
89
- DT_VERNEEDNUM = 0x6fffffff
90
- DT_LOPROC = 0x70000000
91
- DT_HIPROC = 0x7fffffff
53
+ DT_NULL = 0
54
+ DT_NEEDED = 1
55
+ DT_PLTRELSZ = 2
56
+ DT_PLTGOT = 3
57
+ DT_HASH = 4
58
+ DT_STRTAB = 5
59
+ DT_SYMTAB = 6
60
+ DT_RELA = 7
61
+ DT_RELASZ = 8
62
+ DT_RELAENT = 9
63
+ DT_STRSZ = 10
64
+ DT_SYMENT = 11
65
+ DT_INIT = 12
66
+ DT_FINI = 13
67
+ DT_SONAME = 14
68
+ DT_RPATH = 15
69
+ DT_SYMBOLIC = 16
70
+ DT_REL = 17
71
+ DT_RELSZ = 18
72
+ DT_RELENT = 19
73
+ DT_PLTREL = 20
74
+ DT_DEBUG = 21
75
+ DT_TEXTREL = 22
76
+ DT_JMPREL = 23
77
+ DT_BIND_NOW = 24
78
+ DT_INIT_ARRAY = 25
79
+ DT_FINI_ARRAY = 26
80
+ DT_INIT_ARRAYSZ = 27
81
+ DT_FINI_ARRAYSZ = 28
82
+ DT_RUNPATH = 29
83
+ DT_FLAGS = 30
84
+ DT_ENCODING = 32
85
+ DT_LOOS = 0x6000000d
86
+ DT_HIOS = 0x6ffff000
87
+ DT_VALRNGLO = 0x6ffffd00
88
+ DT_VALRNGHI = 0x6ffffdff
89
+ DT_ADDRRNGLO = 0x6ffffe00
90
+ DT_ADDRRNGHI = 0x6ffffeff
91
+ DT_VERSYM = 0x6ffffff0
92
+ DT_RELACOUNT = 0x6ffffff9
93
+ DT_RELCOUNT = 0x6ffffffa
94
+ DT_FLAGS_1 = 0x6ffffffb
95
+ DT_VERDEF = 0x6ffffffc
96
+ DT_VERDEFNUM = 0x6ffffffd
97
+ DT_VERNEED = 0x6ffffffe
98
+ DT_VERNEEDNUM = 0x6fffffff
99
+ DT_LOPROC = 0x70000000
100
+ DT_HIPROC = 0x7fffffff
92
101
  end
93
102
  include DT
94
103
 
@@ -178,5 +187,27 @@ module ELFTools
178
187
  end
179
188
  end
180
189
  include EM
190
+
191
+ # This module defines elf file types.
192
+ module ET
193
+ ET_NONE = 0
194
+ ET_REL = 1
195
+ ET_EXEC = 2
196
+ ET_DYN = 3
197
+ ET_CORE = 4
198
+ # Return the type name according to +e_type+ in ELF file header.
199
+ # @return [String] Type in string format.
200
+ def self.mapping(type)
201
+ case type
202
+ when Constants::ET_NONE then 'NONE'
203
+ when Constants::ET_REL then 'REL'
204
+ when Constants::ET_EXEC then 'EXEC'
205
+ when Constants::ET_DYN then 'DYN'
206
+ when Constants::ET_CORE then 'CORE'
207
+ else '<unknown>'
208
+ end
209
+ end
210
+ end
211
+ include ET
181
212
  end
182
213
  end
@@ -14,18 +14,27 @@ module ELFTools
14
14
  # header
15
15
  # tag_start
16
16
  # @param [Block] block You can give a block.
17
- # @return [Array<ELFTools::Dynamic::Tag>] Array of tags.
17
+ # @return [Enumerator<ELFTools::Dynamic::Tag>, Array<ELFTools::Dynamic::Tag>]
18
+ # If block is not given, an enumerator will be returned.
19
+ # Otherwise, return array of tags.
18
20
  def each_tags
21
+ return enum_for(:each_tags) unless block_given?
19
22
  arr = []
20
23
  0.step do |i|
21
24
  tag = tag_at(i)
22
- yield tag if block_given?
25
+ yield tag
23
26
  arr << tag
24
27
  break if tag.header.d_tag == ELFTools::Constants::DT_NULL
25
28
  end
26
29
  arr
27
30
  end
28
- alias tags each_tags
31
+
32
+ # Use {#tags} to get all tags.
33
+ # @return [Array<ELFTools::Dynamic::Tag>]
34
+ # Array of tags.
35
+ def tags
36
+ each_tags.to_a
37
+ end
29
38
 
30
39
  # Get a tag of specific type.
31
40
  # @param [Integer, Symbol, String] type
@@ -53,10 +62,7 @@ module ELFTools
53
62
  # #=> #<ELFTools::Dynamic::Tag:0x0055d3d2d91b28 @header={:d_tag=>3, :d_val=>6295552}>
54
63
  def tag_by_type(type)
55
64
  type = Util.to_constant(Constants::DT, type)
56
- each_tags do |tag|
57
- return tag if tag.header.d_tag == type
58
- end
59
- nil
65
+ each_tags.find { |tag| tag.header.d_tag == type }
60
66
  end
61
67
 
62
68
  # Get the +n+-th tag.
@@ -75,10 +81,10 @@ module ELFTools
75
81
  return if n < 0
76
82
  @tag_at_map ||= {}
77
83
  return @tag_at_map[n] if @tag_at_map[n]
78
- dyn = ELF_Dyn.new(endian: endian)
84
+ dyn = Structs::ELF_Dyn.new(endian: endian)
79
85
  dyn.elf_class = header.elf_class
80
86
  stream.pos = tag_start + n * dyn.num_bytes
81
- @tag_at_map[n] = Tag.new(dyn.read(stream), stream)
87
+ @tag_at_map[n] = Tag.new(dyn.read(stream), stream, method(:str_offset))
82
88
  end
83
89
 
84
90
  private
@@ -87,20 +93,68 @@ module ELFTools
87
93
  header.class.self_endian
88
94
  end
89
95
 
96
+ # Get the DT_STRTAB's +d_val+ offset related to file.
97
+ def str_offset
98
+ # TODO: handle DT_STRTAB not exitsts.
99
+ @str_offset ||= @offset_from_vma.call(tag_by_type(:strtab).header.d_val.to_i)
100
+ end
101
+
90
102
  # A tag class.
91
103
  class Tag
92
- attr_reader :header # @return [ELFTools::ELF_Dyn] The dynamic tag header.
104
+ attr_reader :header # @return [ELFTools::Structs::ELF_Dyn] The dynamic tag header.
93
105
  attr_reader :stream # @return [File] Streaming object.
94
106
 
95
107
  # Instantiate a {ELFTools::Dynamic::Tag} object.
96
108
  # @param [ELF_Dyn] header The dynamic tag header.
97
109
  # @param [File] stream Streaming object.
98
- def initialize(header, stream)
110
+ # @param [Method] str_offset
111
+ # Call this method to get the string offset related
112
+ # to file.
113
+ def initialize(header, stream, str_offset)
99
114
  @header = header
100
115
  @stream = stream
116
+ @str_offset = str_offset
117
+ end
118
+
119
+ TYPE_WITH_NAME = [Constants::DT_NEEDED,
120
+ Constants::DT_SONAME,
121
+ Constants::DT_RPATH,
122
+ Constants::DT_RUNPATH].freeze
123
+ # Return the content of this tag records.
124
+ #
125
+ # For normal tags, this method just return
126
+ # +header.d_val+. For tags with +header.d_val+
127
+ # in meaning of string offset (e.g. DT_NEEDED), this method would
128
+ # return the string it specified.
129
+ # Tags with type in {TYPE_WITH_NAME} are those tags with name.
130
+ # @return [Integer, String] The content this tag records.
131
+ # @example
132
+ # dynamic = elf.segment_by_type(:dynamic)
133
+ # dynamic.tag_by_type(:init).value
134
+ # #=> 4195600 # 0x400510
135
+ # dynamic.tag_by_type(:needed).value
136
+ # #=> 'libc.so.6'
137
+ def value
138
+ name || header.d_val.to_i
139
+ end
140
+
141
+ # Is this tag has a name?
142
+ #
143
+ # The criteria here is if this tag's type is in {TYPE_WITH_NAME}.
144
+ # @return [Boolean] Is this tag has a name.
145
+ def name?
146
+ TYPE_WITH_NAME.include?(header.d_tag)
147
+ end
148
+
149
+ # Return the name of this tag.
150
+ #
151
+ # Only tags with name would return a name.
152
+ # Others would return +nil+.
153
+ # @return [String, NilClass] The name.
154
+ def name
155
+ return nil unless name?
156
+ Util.cstring(stream, @str_offset.call + header.d_val.to_i)
101
157
  end
102
- # TODO: Get the name of tags, e.g. SONAME
103
- # TODO: Handle (non)-PIE ELF correctly.
104
158
  end
105
159
  end
106
160
  end
@@ -3,7 +3,7 @@ require 'elftools/exceptions'
3
3
  require 'elftools/lazy_array'
4
4
  require 'elftools/sections/sections'
5
5
  require 'elftools/segments/segments'
6
- require 'elftools/structures'
6
+ require 'elftools/structs'
7
7
 
8
8
  module ELFTools
9
9
  # The main class for using elftools.
@@ -27,11 +27,11 @@ module ELFTools
27
27
  # Return the file header.
28
28
  #
29
29
  # Lazy loading.
30
- # @retrn [ELFTools::ELF_Ehdr] The header.
30
+ # @retrn [ELFTools::Structs::ELF_Ehdr] The header.
31
31
  def header
32
- return @header if @header
32
+ return @header if defined?(@header)
33
33
  stream.pos = 0
34
- @header = ELF_Ehdr.new(endian: endian)
34
+ @header = Structs::ELF_Ehdr.new(endian: endian)
35
35
  @header.elf_class = elf_class
36
36
  @header.read(stream)
37
37
  end
@@ -65,6 +65,17 @@ module ELFTools
65
65
  ELFTools::Constants::EM.mapping(header.e_machine)
66
66
  end
67
67
 
68
+ # Return the ELF type according to +e_type+.
69
+ # @return [String] Type in string format.
70
+ # @example
71
+ # ELFFile.new(File.open('spec/files/libc.so.6')).elf_type
72
+ # #=> 'DYN'
73
+ # ELFFile.new(File.open('spec/files/amd64.elf')).elf_type
74
+ # #=> 'EXEC'
75
+ def elf_type
76
+ ELFTools::Constants::ET.mapping(header.e_type)
77
+ end
78
+
68
79
  #========= method about sections
69
80
 
70
81
  # Number of sections in this file.
@@ -87,13 +98,7 @@ module ELFTools
87
98
  # elf.section_by_name('no such section')
88
99
  # #=> nil
89
100
  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
101
+ each_sections.find { |sec| sec.name == name }
97
102
  end
98
103
 
99
104
  # Iterate all sections.
@@ -104,17 +109,24 @@ module ELFTools
104
109
  # since not all sections need to be created.
105
110
  # @param [Block] block
106
111
  # Just like +Array#each+, you can give a block.
107
- # @return [ Array<ELFTools::Sections::Section>]
108
- # The whole sections will be returned.
112
+ # @return [Enumerator<ELFTools::Sections::Section>, Array<ELFTools::Sections::Section>]
113
+ # As +Array#each+, if block is not given, a enumerator will be returned,
114
+ # otherwise, the whole sections will be returned.
109
115
  def each_sections
116
+ return enum_for(:each_sections) unless block_given?
110
117
  Array.new(num_sections) do |i|
111
118
  sec = section_at(i)
112
- block_given? ? yield(sec) : sec
119
+ yield sec
120
+ sec
113
121
  end
114
122
  end
115
123
 
116
- # Simply use {#sections} without giving block to get all sections.
117
- alias sections each_sections
124
+ # Simply use {#sections} to get all sections.
125
+ # @return [Array<ELFTools::Sections::Section>]
126
+ # Whole sections.
127
+ def sections
128
+ each_sections.to_a
129
+ end
118
130
 
119
131
  # Acquire the +n+-th section, 0-based.
120
132
  #
@@ -128,6 +140,26 @@ module ELFTools
128
140
  @sections[n]
129
141
  end
130
142
 
143
+ # Fetch all sections with specific type.
144
+ #
145
+ # The available types are listed in {ELFTools::Constants},
146
+ # start with +SHT_+.
147
+ # This method accept giving block.
148
+ # @param [Integer, Symbol, String] type
149
+ # The type needed, similar format as {#segment_by_type}.
150
+ # @param [Block] block
151
+ # Block will be yielded whenever find a section.
152
+ # @return [Array<ELFTools::Sections::section>] The target sections.
153
+ # @example
154
+ # elf = ELFTools::ELFFile.new(File.open('spec/files/amd64.elf'))
155
+ # elf.sections_by_type(:rela)
156
+ # #=> [#<ELFTools::Sections::RelocationSection:0x00563cd3219970>,
157
+ # # #<ELFTools::Sections::RelocationSection:0x00563cd3b89d70>]
158
+ def sections_by_type(type, &block)
159
+ type = Util.to_constant(Constants::SHT, type)
160
+ Util.select_by_type(each_sections, type, &block)
161
+ end
162
+
131
163
  # Get the string table section.
132
164
  #
133
165
  # This section is acquired by using the +e_shstrndx+
@@ -156,18 +188,24 @@ module ELFTools
156
188
  # @return [Array<ELFTools::Segments::Segment>]
157
189
  # Whole segments will be returned.
158
190
  def each_segments
191
+ return enum_for(:each_segments) unless block_given?
159
192
  Array.new(num_segments) do |i|
160
193
  seg = segment_at(i)
161
- block_given? ? yield(seg) : seg
194
+ yield seg
195
+ seg
162
196
  end
163
197
  end
164
198
 
165
- # Simply use {#segments} without giving block to get all segments.
166
- alias segments each_segments
199
+ # Simply use {#segments} to get all segments.
200
+ # @return [Array<ELFTools::Segments::Segment>]
201
+ # Whole segments.
202
+ def segments
203
+ each_segments.to_a
204
+ end
167
205
 
168
206
  # Get the first segment with +p_type=type+.
169
207
  # The available types are listed in {ELFTools::Constants},
170
- # starts with +PT_+.
208
+ # start with +PT_+.
171
209
  #
172
210
  # Notice: this method will return the first segment found,
173
211
  # to found all segments with specific type you can use {#segments_by_type}.
@@ -208,21 +246,22 @@ module ELFTools
208
246
  # #=> nil # no such segment exists
209
247
  def segment_by_type(type)
210
248
  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
249
+ each_segments.find { |seg| seg.header.p_type == type }
215
250
  end
216
251
 
217
252
  # Fetch all segments with specific type.
253
+ #
218
254
  # If you want to find only one segment,
219
255
  # use {#segment_by_type} instead.
256
+ # This method accept giving block.
220
257
  # @param [Integer, Symbol, String] type
221
258
  # The type needed, same format as {#segment_by_type}.
259
+ # @param [Block] block
260
+ # Block will be yielded whenever find a segement.
222
261
  # @return [Array<ELFTools::Segments::Segment>] The target segments.
223
- def segments_by_type(type)
262
+ def segments_by_type(type, &block)
224
263
  type = Util.to_constant(Constants::PT, type)
225
- segments.select { |segment| segment.header.p_type == type }
264
+ Util.select_by_type(each_segments, type, &block)
226
265
  end
227
266
 
228
267
  # Acquire the +n+-th segment, 0-based.
@@ -237,6 +276,25 @@ module ELFTools
237
276
  @segments[n]
238
277
  end
239
278
 
279
+ # Get the offset related to file, given virtual memory address.
280
+ #
281
+ # This method should work no matter ELF is a PIE or not.
282
+ # This method refers from (actually equals to) binutils/readelf.c#offset_from_vma.
283
+ # @param [Integer] vma The address need query.
284
+ # @return [Integer] Offset related to file.
285
+ # @example
286
+ # elf = ELFTools::ELFFile.new(File.open('/bin/cat'))
287
+ # elf.offset_from_vma(0x401337)
288
+ # #=> 4919 # 0x1337
289
+ def offset_from_vma(vma, size = 0)
290
+ segments_by_type(:load) do |seg|
291
+ if vma >= (seg.header.p_vaddr & -seg.header.p_align) &&
292
+ vma + size <= seg.header.p_vaddr + seg.header.p_filesz
293
+ return vma - seg.header.p_vaddr + seg.header.p_offset
294
+ end
295
+ end
296
+ end
297
+
240
298
  private
241
299
 
242
300
  def identify
@@ -259,19 +317,20 @@ module ELFTools
259
317
 
260
318
  def create_section(n)
261
319
  stream.pos = header.e_shoff + n * header.e_shentsize
262
- shdr = ELF_Shdr.new(endian: endian)
320
+ shdr = Structs::ELF_Shdr.new(endian: endian)
263
321
  shdr.elf_class = elf_class
264
322
  shdr.read(stream)
265
323
  Sections::Section.create(shdr, stream,
324
+ offset_from_vma: method(:offset_from_vma),
266
325
  strtab: method(:strtab_section),
267
326
  section_at: method(:section_at))
268
327
  end
269
328
 
270
329
  def create_segment(n)
271
330
  stream.pos = header.e_phoff + n * header.e_phentsize
272
- phdr = ELF_Phdr[elf_class].new(endian: endian)
331
+ phdr = Structs::ELF_Phdr[elf_class].new(endian: endian)
273
332
  phdr.elf_class = elf_class
274
- Segments::Segment.create(phdr.read(stream), stream)
333
+ Segments::Segment.create(phdr.read(stream), stream, offset_from_vma: method(:offset_from_vma))
275
334
  end
276
335
  end
277
336
  end
@@ -1,4 +1,4 @@
1
- require 'elftools/structures'
1
+ require 'elftools/structs'
2
2
  require 'elftools/util'
3
3
 
4
4
  module ELFTools
@@ -10,10 +10,10 @@ module ELFTools
10
10
  # {ELFTools::Segments::NoteSegment} since some methods assume some attributes already
11
11
  # exist.
12
12
  module Note
13
- # Since size of {ELFTools::ELF_Nhdr} will not change no
13
+ # Since size of {ELFTools::Structs::ELF_Nhdr} will not change no
14
14
  # matter what endian and what arch, we can do this here.
15
15
  # This value should equal to 12.
16
- SIZE_OF_NHDR = ELF_Nhdr.new(endian: :little).num_bytes
16
+ SIZE_OF_NHDR = Structs::ELF_Nhdr.new(endian: :little).num_bytes
17
17
 
18
18
  # Iterate all notes in a note section or segment.
19
19
  #
@@ -68,13 +68,13 @@ module ELFTools
68
68
  end
69
69
 
70
70
  def create_note(cur)
71
- nhdr = ELF_Nhdr.new(endian: endian).read(stream)
71
+ nhdr = Structs::ELF_Nhdr.new(endian: endian).read(stream)
72
72
  ELFTools::Note::Note.new(nhdr, stream, cur)
73
73
  end
74
74
 
75
75
  # Class of a note.
76
76
  class Note
77
- attr_reader :header # @return [ELFTools::ELF_Nhdr] Note header.
77
+ attr_reader :header # @return [ELFTools::Structs::ELF_Nhdr] Note header.
78
78
  attr_reader :stream # @return [File] Streaming object.
79
79
  attr_reader :offset # @return [Integer] Address of this note start, includes note header.
80
80
 
@@ -0,0 +1,108 @@
1
+ require 'elftools/constants'
2
+ require 'elftools/sections/section'
3
+ require 'elftools/structs'
4
+
5
+ module ELFTools
6
+ module Sections
7
+ # Class of note section.
8
+ # Note section records notes
9
+ class RelocationSection < Section
10
+ # Is this relocation a RELA or REL type.
11
+ # @return [Boolean] If is RELA.
12
+ def rela?
13
+ header.sh_type == Constants::SHT_RELA
14
+ end
15
+
16
+ # Number of relocations in this section.
17
+ # @return [Integer] The number.
18
+ def num_relocations
19
+ header.sh_size / header.sh_entsize
20
+ end
21
+
22
+ # Acquire the +n+-th relocation, 0-based.
23
+ #
24
+ # relocations are lazy loaded.
25
+ # @param [Integer] n The index.
26
+ # @return [ELFTools::Relocation, NilClass]
27
+ # The target relocation.
28
+ # If +n+ is out of bound, +nil+ is returned.
29
+ def relocation_at(n)
30
+ @relocations ||= LazyArray.new(num_relocations, &method(:create_relocation))
31
+ @relocations[n]
32
+ end
33
+
34
+ # Iterate all relocations.
35
+ #
36
+ # All relocations are lazy loading, the relocation
37
+ # only be created whenever accessing it.
38
+ # @param [Block] block
39
+ # Just like +Array#each+, you can give a block.
40
+ # @return [Enumerator<ELFTools::Relocation>, Array<ELFTools::Relocation>]
41
+ # If block is not given, an enumerator will be returned.
42
+ # Otherwise, the whole relocations will be returned.
43
+ def each_relocations
44
+ return enum_for(:each_relocations) unless block_given?
45
+ Array.new(num_relocations) do |i|
46
+ rel = relocation_at(i)
47
+ yield rel
48
+ rel
49
+ end
50
+ end
51
+
52
+ # Simply use {#relocations} to get all relocations.
53
+ # @return [Array<ELFTools::Relocation>]
54
+ # Whole relocations.
55
+ def relocations
56
+ each_relocations.to_a
57
+ end
58
+
59
+ private
60
+
61
+ def create_relocation(n)
62
+ stream.pos = header.sh_offset + n * header.sh_entsize
63
+ klass = rela? ? Structs::ELF_Rela : Structs::ELF_Rel
64
+ rel = klass.new(endian: header.class.self_endian)
65
+ rel.elf_class = header.elf_class
66
+ rel.read(stream)
67
+ Relocation.new(rel, stream)
68
+ end
69
+ end
70
+ end
71
+
72
+ # A relocation entry.
73
+ #
74
+ # Can be either a REL or RELA relocation.
75
+ # XXX: move this to an independent file?
76
+ class Relocation
77
+ attr_reader :header # @return [ELFTools::Structs::ELF_Rel, ELFTools::Structs::ELF_Rela] Rel(a) header.
78
+ attr_reader :stream # @return [File] Streaming object.
79
+
80
+ # Instantiate a {Relocation} object.
81
+ def initialize(header, stream)
82
+ @header = header
83
+ @stream = stream
84
+ end
85
+
86
+ # +r_info+ contains sym and type, use two methods
87
+ # to access them easier.
88
+ # @return [Integer] sym infor.
89
+ def r_info_sym
90
+ header.r_info >> mask_bit
91
+ end
92
+ alias symbol_index r_info_sym
93
+
94
+ # +r_info+ contains sym and type, use two methods
95
+ # to access them easier.
96
+ # @return [Integer] type infor.
97
+ def r_info_type
98
+ header.r_info & ((1 << mask_bit) - 1)
99
+ end
100
+ alias type r_info_type
101
+
102
+ private
103
+
104
+ def mask_bit
105
+ header.elf_class == 32 ? 8 : 32
106
+ end
107
+ end
108
+ end
@@ -3,11 +3,11 @@ module ELFTools
3
3
  module Sections
4
4
  # Base class of sections.
5
5
  class Section
6
- attr_reader :header # @return [ELFTools::ELF_Shdr] Section header.
6
+ attr_reader :header # @return [ELFTools::Structs::ELF_Shdr] Section header.
7
7
  attr_reader :stream # @return [File] Streaming object.
8
8
 
9
9
  # Instantiate a {Section} object.
10
- # @param [ELFTools::ELF_Shdr] header
10
+ # @param [ELFTools::Structs::ELF_Shdr] header
11
11
  # The section header object.
12
12
  # @param [File] stream
13
13
  # The streaming object for further dump.
@@ -15,10 +15,20 @@ module ELFTools
15
15
  # The string table object. For fetching section names.
16
16
  # If +Proc+ if given, it will call at the first
17
17
  # time access +#name+.
18
- def initialize(header, stream, strtab: nil, **_kwagrs)
18
+ # @param [Method] offset_from_vma
19
+ # The method to get offset of file, given virtual memory address.
20
+ def initialize(header, stream, offset_from_vma: nil, strtab: nil, **_kwargs)
19
21
  @header = header
20
22
  @stream = stream
21
23
  @strtab = strtab
24
+ @offset_from_vma = offset_from_vma
25
+ end
26
+
27
+ # Return +header.sh_type+ in a simplier way.
28
+ # @return [Integer]
29
+ # The type, meaning of types are defined in {Constants::SHT}.
30
+ def type
31
+ header.sh_type
22
32
  end
23
33
 
24
34
  # Get name of this section.
@@ -5,6 +5,7 @@ require 'elftools/sections/section'
5
5
  require 'elftools/sections/dynamic_section'
6
6
  require 'elftools/sections/note_section'
7
7
  require 'elftools/sections/null_section'
8
+ require 'elftools/sections/relocation_section'
8
9
  require 'elftools/sections/str_tab_section'
9
10
  require 'elftools/sections/sym_tab_section'
10
11
 
@@ -14,7 +15,7 @@ module ELFTools
14
15
  # Class methods of {Sections::Section}.
15
16
  class << Section
16
17
  # Use different class according to +header.sh_type+.
17
- # @param [ELFTools::ELF_Shdr] header Section header.
18
+ # @param [ELFTools::Structs::ELF_Shdr] header Section header.
18
19
  # @param [File] stream Streaming object.
19
20
  # @return [ELFTools::Sections::Section]
20
21
  # Return object dependes on +header.sh_type+.
@@ -23,6 +24,7 @@ module ELFTools
23
24
  when Constants::SHT_DYNAMIC then DynamicSection
24
25
  when Constants::SHT_NULL then NullSection
25
26
  when Constants::SHT_NOTE then NoteSection
27
+ when Constants::SHT_RELA, Constants::SHT_REL then RelocationSection
26
28
  when Constants::SHT_STRTAB then StrTabSection
27
29
  when Constants::SHT_SYMTAB, Constants::SHT_DYNSYM then SymTabSection
28
30
  else Section
@@ -1,4 +1,5 @@
1
1
  require 'elftools/sections/section'
2
+ require 'elftools/util'
2
3
 
3
4
  module ELFTools
4
5
  module Sections
@@ -11,16 +12,7 @@ module ELFTools
11
12
  # Usually from +shdr.sh_name+ or +sym.st_name+.
12
13
  # @return [String] The name without null bytes.
13
14
  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
15
+ Util.cstring(stream, header.sh_offset + offset)
24
16
  end
25
17
  end
26
18
  end
@@ -9,7 +9,7 @@ module ELFTools
9
9
  # Instantiate a {SymTabSection} object.
10
10
  # There's a +section_at+ lambda for {SymTabSection}
11
11
  # to easily fetch other sections.
12
- # @param [ELFTools::ELF_Shdr] header
12
+ # @param [ELFTools::Structs::ELF_Shdr] header
13
13
  # See {Section#initialize} for more information.
14
14
  # @param [File] stream
15
15
  # See {Section#initialize} for more information.
@@ -36,7 +36,7 @@ module ELFTools
36
36
  #
37
37
  # Symbols are lazy loaded.
38
38
  # @param [Integer] n The index.
39
- # @return [ELFTools:Symbol, NilClass]
39
+ # @return [ELFTools::Symbol, NilClass]
40
40
  # The target symbol.
41
41
  # If +n+ is out of bound, +nil+ is returned.
42
42
  def symbol_at(n)
@@ -87,20 +87,21 @@ module ELFTools
87
87
 
88
88
  def create_symbol(n)
89
89
  stream.pos = header.sh_offset + n * header.sh_entsize
90
- sym = ELF_sym[header.elf_class].new(endian: header.class.self_endian)
90
+ sym = Structs::ELF_sym[header.elf_class].new(endian: header.class.self_endian)
91
91
  sym.read(stream)
92
92
  Symbol.new(sym, stream, symstr: method(:symstr))
93
93
  end
94
94
  end
95
95
 
96
96
  # Class of symbol.
97
+ #
97
98
  # XXX: Should this class be defined in an independent file?
98
99
  class Symbol
99
- attr_reader :header # @return [ELFTools::ELF32_sym, ELFTools::ELF64_sym] Section header.
100
+ attr_reader :header # @return [ELFTools::Structs::ELF32_sym, ELFTools::Structs::ELF64_sym] Section header.
100
101
  attr_reader :stream # @return [File] Streaming object.
101
102
 
102
103
  # Instantiate a {ELFTools::Symbol} object.
103
- # @param [ELFTools::ELF32_sym, ELFTools::ELF64_sym] header
104
+ # @param [ELFTools::Structs::ELF32_sym, ELFTools::Structs::ELF64_sym] header
104
105
  # The symbol header.
105
106
  # @param [File] stream The streaming object.
106
107
  # @param [ELFTools::Sections::StrTabSection, Proc] symstr
@@ -2,17 +2,27 @@ module ELFTools
2
2
  module Segments
3
3
  # Base class of segments.
4
4
  class Segment
5
- attr_reader :header # @return [ELFTools::ELF32_Phdr, ELFTools::ELF64_Phdr] Program header.
5
+ attr_reader :header # @return [ELFTools::Structs::ELF32_Phdr, ELFTools::Structs::ELF64_Phdr] Program header.
6
6
  attr_reader :stream # @return [File] Streaming object.
7
7
 
8
8
  # Instantiate a {Segment} object.
9
- # @param [ELFTools::ELF32_Phdr, ELFTools::ELF64_Phdr] header
9
+ # @param [ELFTools::Structs::ELF32_Phdr, ELFTools::Structs::ELF64_Phdr] header
10
10
  # Program header.
11
11
  # @param [File] stream
12
12
  # Streaming object.
13
- def initialize(header, stream)
13
+ # @param [Method] offset_from_vma
14
+ # The method to get offset of file, given virtual memory address.
15
+ def initialize(header, stream, offset_from_vma: nil)
14
16
  @header = header
15
17
  @stream = stream
18
+ @offset_from_vma = offset_from_vma
19
+ end
20
+
21
+ # Return +header.p_type+ in a simplier way.
22
+ # @return [Integer]
23
+ # The type, meaning of types are defined in {Constants::PT}.
24
+ def type
25
+ header.p_type
16
26
  end
17
27
 
18
28
  # The content in this segment.
@@ -12,7 +12,7 @@ module ELFTools
12
12
  # Class methods of {Segments::Segment}.
13
13
  class << Segment
14
14
  # Use different class according to +header.p_type+.
15
- # @param [ELFTools::ELF32_Phdr, ELFTools::ELF64_Phdr] header Program header of a segment.
15
+ # @param [ELFTools::Structs::ELF32_Phdr, ELFTools::Structs::ELF64_Phdr] header Program header of a segment.
16
16
  # @param [File] stream Streaming object.
17
17
  # @return [ELFTools::Segments::Segment]
18
18
  # Return object dependes on +header.p_type+.
@@ -0,0 +1,155 @@
1
+ require 'bindata'
2
+ module ELFTools
3
+ # Define ELF related structures in this module.
4
+ #
5
+ # Structures are fetch from https://github.com/torvalds/linux/blob/master/include/uapi/linux/elf.h.
6
+ # Using the bindata gem to make these structures support 32/64 bits and
7
+ # little/big endian simultaneously.
8
+ module Structs
9
+ # The base structure to define common methods.
10
+ class ELFStruct < BinData::Record
11
+ CHOICE_SIZE_T = {
12
+ selection: :elf_class, choices: { 32 => :uint32, 64 => :uint64 }
13
+ }.freeze
14
+
15
+ attr_accessor :elf_class # @return [Integer] 32 or 64.
16
+
17
+ # Hacking to get endian of current class
18
+ # @return [Symbol, NilClass] +:little+ or +:big+.
19
+ def self.self_endian
20
+ bindata_name[-2..-1] == 'ge' ? :big : :little
21
+ end
22
+ end
23
+
24
+ # ELF header structure.
25
+ class ELF_Ehdr < ELFStruct
26
+ endian :big_and_little
27
+ struct :e_ident do
28
+ string :magic, read_length: 4
29
+ int8 :ei_class
30
+ int8 :ei_data
31
+ int8 :ei_version
32
+ int8 :ei_osabi
33
+ int8 :ei_abiversion
34
+ string :ei_padding, read_length: 7 # no use
35
+ end
36
+ uint16 :e_type
37
+ uint16 :e_machine
38
+ uint32 :e_version
39
+ # entry point
40
+ choice :e_entry, **CHOICE_SIZE_T
41
+ choice :e_phoff, **CHOICE_SIZE_T
42
+ choice :e_shoff, **CHOICE_SIZE_T
43
+ uint32 :e_flags
44
+ uint16 :e_ehsize # size of this header
45
+ uint16 :e_phentsize # size of each segment
46
+ uint16 :e_phnum # number of segments
47
+ uint16 :e_shentsize # size of each section
48
+ uint16 :e_shnum # number of sections
49
+ uint16 :e_shstrndx # index of string table section
50
+ end
51
+
52
+ # Section header structure.
53
+ class ELF_Shdr < ELFStruct
54
+ endian :big_and_little
55
+ uint32 :sh_name
56
+ uint32 :sh_type
57
+ choice :sh_flags, **CHOICE_SIZE_T
58
+ choice :sh_addr, **CHOICE_SIZE_T
59
+ choice :sh_offset, **CHOICE_SIZE_T
60
+ choice :sh_size, **CHOICE_SIZE_T
61
+ uint32 :sh_link
62
+ uint32 :sh_info
63
+ choice :sh_addralign, **CHOICE_SIZE_T
64
+ choice :sh_entsize, **CHOICE_SIZE_T
65
+ end
66
+
67
+ # Program header structure for 32bit.
68
+ class ELF32_Phdr < ELFStruct
69
+ endian :big_and_little
70
+ uint32 :p_type
71
+ uint32 :p_offset
72
+ uint32 :p_vaddr
73
+ uint32 :p_paddr
74
+ uint32 :p_filesz
75
+ uint32 :p_memsz
76
+ uint32 :p_flags
77
+ uint32 :p_align
78
+ end
79
+
80
+ # Program header structure for 64bit.
81
+ class ELF64_Phdr < ELFStruct
82
+ endian :big_and_little
83
+ uint32 :p_type
84
+ uint32 :p_flags
85
+ uint64 :p_offset
86
+ uint64 :p_vaddr
87
+ uint64 :p_paddr
88
+ uint64 :p_filesz
89
+ uint64 :p_memsz
90
+ uint64 :p_align
91
+ end
92
+ ELF_Phdr = {
93
+ 32 => ELF32_Phdr,
94
+ 64 => ELF64_Phdr
95
+ }.freeze
96
+
97
+ # Symbol structure for 32bit.
98
+ class ELF32_sym < ELFStruct
99
+ endian :big_and_little
100
+ uint32 :st_name
101
+ uint32 :st_value
102
+ uint32 :st_size
103
+ uint8 :st_info
104
+ uint8 :st_other
105
+ uint16 :st_shndx
106
+ end
107
+
108
+ # Symbol structure for 64bit.
109
+ class ELF64_sym < ELFStruct
110
+ endian :big_and_little
111
+ uint32 :st_name # Symbol name, index in string tbl
112
+ uint8 :st_info # Type and binding attributes
113
+ uint8 :st_other # No defined meaning, 0
114
+ uint16 :st_shndx # Associated section index
115
+ uint64 :st_value # Value of the symbol
116
+ uint64 :st_size # Associated symbol size
117
+ end
118
+ ELF_sym = {
119
+ 32 => ELF32_sym,
120
+ 64 => ELF64_sym
121
+ }.freeze
122
+
123
+ # Note header.
124
+ class ELF_Nhdr < ELFStruct
125
+ endian :big_and_little
126
+ uint32 :n_namesz # Name size
127
+ uint32 :n_descsz # Content size
128
+ uint32 :n_type # Content type
129
+ end
130
+
131
+ # Dynamic tag header.
132
+ class ELF_Dyn < ELFStruct
133
+ endian :big_and_little
134
+ choice :d_tag, selection: :elf_class, choices: { 32 => :int32, 64 => :int64 }
135
+ # This is an union type named +d_un+ in original source,
136
+ # simplify it to be +d_val+ here.
137
+ choice :d_val, **CHOICE_SIZE_T
138
+ end
139
+
140
+ # Rel header in .rel section.
141
+ class ELF_Rel < ELFStruct
142
+ endian :big_and_little
143
+ choice :r_offset, **CHOICE_SIZE_T
144
+ choice :r_info, **CHOICE_SIZE_T
145
+ end
146
+
147
+ # Rela header in .rela section.
148
+ class ELF_Rela < ELFStruct
149
+ endian :big_and_little
150
+ choice :r_offset, **CHOICE_SIZE_T
151
+ choice :r_info, **CHOICE_SIZE_T
152
+ choice :r_addend, selection: :elf_class, choices: { 32 => :int32, 64 => :int64 }
153
+ end
154
+ end
155
+ end
@@ -45,6 +45,48 @@ module ELFTools
45
45
  raise ArgumentError, "No constants in #{module_name} named \"#{val}\"" unless mod.const_defined?(val)
46
46
  mod.const_get(val)
47
47
  end
48
+
49
+ # Read from stream until reach a null-byte.
50
+ # @param [File] stream Streaming object
51
+ # @param [Integer] offset Start from here.
52
+ # @return [String] Result string will never contain null byte.
53
+ # @example
54
+ # Util.cstring(File.open('/bin/cat'), 0)
55
+ # #=> "\x7FELF\x02\x01\x01"
56
+ def cstring(stream, offset)
57
+ stream.pos = offset
58
+ # read until "\x00"
59
+ ret = ''
60
+ loop do
61
+ c = stream.read(1)
62
+ return nil if c.nil? # reach EOF
63
+ break if c == "\x00"
64
+ ret += c
65
+ end
66
+ ret
67
+ end
68
+
69
+ # Select objects from enumerator with +.type+ property
70
+ # equals to +type+.
71
+ #
72
+ # Different from naive +Array#select+ is this method
73
+ # will yield block whenever find a desired object.
74
+ #
75
+ # This method is used to simplify the same logic in methods
76
+ # {ELFFile#sections_by_type}, {ELFFile#segments_by_type}, etc.
77
+ # @param [Enumerator] enum An enumerator for further select.
78
+ # @param [Object] type The type you want.
79
+ # @return [Array<Object>]
80
+ # The return value will be objects in +enum+ with attribute
81
+ # +.type+ equals to +type+.
82
+ def select_by_type(enum, type)
83
+ enum.select do |sec|
84
+ if sec.type == type
85
+ yield sec if block_given?
86
+ true
87
+ end
88
+ end
89
+ end
48
90
  end
49
91
  extend ClassMethods
50
92
  end
@@ -1,3 +1,3 @@
1
1
  module ELFTools
2
- VERSION = '0.1.0'.freeze
2
+ VERSION = '0.2.0'.freeze
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: elftools
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - david942j
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-03-16 00:00:00.000000000 Z
11
+ date: 2017-03-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bindata
@@ -114,6 +114,7 @@ files:
114
114
  - lib/elftools/sections/dynamic_section.rb
115
115
  - lib/elftools/sections/note_section.rb
116
116
  - lib/elftools/sections/null_section.rb
117
+ - lib/elftools/sections/relocation_section.rb
117
118
  - lib/elftools/sections/section.rb
118
119
  - lib/elftools/sections/sections.rb
119
120
  - lib/elftools/sections/str_tab_section.rb
@@ -123,7 +124,7 @@ files:
123
124
  - lib/elftools/segments/note_segment.rb
124
125
  - lib/elftools/segments/segment.rb
125
126
  - lib/elftools/segments/segments.rb
126
- - lib/elftools/structures.rb
127
+ - lib/elftools/structs.rb
127
128
  - lib/elftools/util.rb
128
129
  - lib/elftools/version.rb
129
130
  homepage: https://github.com/david942j/rbelftools
@@ -1,133 +0,0 @@
1
- require 'bindata'
2
- module ELFTools
3
- # The base structure to define common methods.
4
- class ELFStruct < BinData::Record
5
- CHOICE_SIZE_T = {
6
- selection: :elf_class, choices: { 32 => :uint32, 64 => :uint64 }
7
- }.freeze
8
-
9
- attr_accessor :elf_class # @return [Integer] 32 or 64.
10
-
11
- # Hacking to get endian of current class
12
- # @return [Symbol, NilClass] +:little+ or +:big+.
13
- def self.self_endian
14
- bindata_name[-2..-1] == 'ge' ? :big : :little
15
- end
16
- end
17
-
18
- # ELF header structure.
19
- class ELF_Ehdr < ELFStruct
20
- endian :big_and_little
21
- struct :e_ident do
22
- string :magic, read_length: 4
23
- int8 :ei_class
24
- int8 :ei_data
25
- int8 :ei_version
26
- int8 :ei_osabi
27
- int8 :ei_abiversion
28
- string :ei_padding, read_length: 7 # no use
29
- end
30
- uint16 :e_type
31
- uint16 :e_machine
32
- uint32 :e_version
33
- # entry point
34
- choice :e_entry, **CHOICE_SIZE_T
35
- choice :e_phoff, **CHOICE_SIZE_T
36
- choice :e_shoff, **CHOICE_SIZE_T
37
- uint32 :e_flags
38
- uint16 :e_ehsize # size of this header
39
- uint16 :e_phentsize # size of each segment
40
- uint16 :e_phnum # number of segments
41
- uint16 :e_shentsize # size of each section
42
- uint16 :e_shnum # number of sections
43
- uint16 :e_shstrndx # index of string table section
44
- end
45
-
46
- # Section header structure.
47
- class ELF_Shdr < ELFStruct
48
- endian :big_and_little
49
- uint32 :sh_name
50
- uint32 :sh_type
51
- choice :sh_flags, **CHOICE_SIZE_T
52
- choice :sh_addr, **CHOICE_SIZE_T
53
- choice :sh_offset, **CHOICE_SIZE_T
54
- choice :sh_size, **CHOICE_SIZE_T
55
- uint32 :sh_link
56
- uint32 :sh_info
57
- choice :sh_addralign, **CHOICE_SIZE_T
58
- choice :sh_entsize, **CHOICE_SIZE_T
59
- end
60
-
61
- # Program header structure for 32bit.
62
- class ELF32_Phdr < ELFStruct
63
- endian :big_and_little
64
- uint32 :p_type
65
- uint32 :p_offset
66
- uint32 :p_vaddr
67
- uint32 :p_paddr
68
- uint32 :p_filesz
69
- uint32 :p_memsz
70
- uint32 :p_flags
71
- uint32 :p_align
72
- end
73
-
74
- # Program header structure for 64bit.
75
- class ELF64_Phdr < ELFStruct
76
- endian :big_and_little
77
- uint32 :p_type
78
- uint32 :p_flags
79
- uint64 :p_offset
80
- uint64 :p_vaddr
81
- uint64 :p_paddr
82
- uint64 :p_filesz
83
- uint64 :p_memsz
84
- uint64 :p_align
85
- end
86
- ELF_Phdr = {
87
- 32 => ELF32_Phdr,
88
- 64 => ELF64_Phdr
89
- }.freeze
90
-
91
- # Symbol structure for 32bit.
92
- class ELF32_sym < ELFStruct
93
- endian :big_and_little
94
- uint32 :st_name
95
- uint32 :st_value
96
- uint32 :st_size
97
- uint8 :st_info
98
- uint8 :st_other
99
- uint16 :st_shndx
100
- end
101
-
102
- # Symbol structure for 64bit.
103
- class ELF64_sym < ELFStruct
104
- endian :big_and_little
105
- uint32 :st_name # Symbol name, index in string tbl
106
- uint8 :st_info # Type and binding attributes
107
- uint8 :st_other # No defined meaning, 0
108
- uint16 :st_shndx # Associated section index
109
- uint64 :st_value # Value of the symbol
110
- uint64 :st_size # Associated symbol size
111
- end
112
- ELF_sym = {
113
- 32 => ELF32_sym,
114
- 64 => ELF64_sym
115
- }.freeze
116
-
117
- # Note header.
118
- class ELF_Nhdr < ELFStruct
119
- endian :big_and_little
120
- uint32 :n_namesz # Name size
121
- uint32 :n_descsz # Content size
122
- uint32 :n_type # Content type
123
- end
124
-
125
- # Dynamic tag header.
126
- class ELF_Dyn < ELFStruct
127
- endian :big_and_little
128
- choice :d_tag, selection: :elf_class, choices: { 32 => :int32, 64 => :int64 }
129
- # This is an union type named +d_un+ in original source,
130
- # simplify it to be +d_val+ here.
131
- choice :d_val, **CHOICE_SIZE_T
132
- end
133
- end