elftools 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
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