elftools 1.0.1 → 1.1.3

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
- SHA1:
3
- metadata.gz: 19ea6d2a816767e47ee17390784085a33e1fe331
4
- data.tar.gz: f4af2d0e5552c02ee43d4de74afecd077926532d
2
+ SHA256:
3
+ metadata.gz: ef6779875e27077da47848a95cef46ee26be52e56e763c0850dbd2e22e7e100b
4
+ data.tar.gz: a9b422a4fb0a11a08036e222475110f9a9f6f788ce8c775d6e67d0e6f1b5a9c6
5
5
  SHA512:
6
- metadata.gz: a368bc9ee554c9ca775d8e2d51b121965d242f64d2b2a838d249a3914d0d91ece6a3469c36519fa9fdd5d1347f2ff291917adf43e39f488509f29faac5348eda
7
- data.tar.gz: 8d777854fc6d4f931452aa0e738202496dd9dd7ce01b22e25da1cf40e1e4839f944cdd95de99e5a88cea85fab2eb611859379b5dc78180a4d0ff42ea835c1f13
6
+ metadata.gz: 13f82b3b243a09531408986b1acef31556089bca5927077c9e4d490632229f77cef97f9fdd1eb4343be8dc9bbb9f55e57b3ee51f5da5651009bd4b4ac3724eb5
7
+ data.tar.gz: 276ad11bcc135f067046694da526da5078cfdc0b24137cadeb7d8c52b0ddb462b23ee7d47c97bc08611160d436240c559ff1b4d18b51ed78a0b607c0973dc913
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'elftools/constants'
2
4
  require 'elftools/elf_file'
3
5
  require 'elftools/version'
@@ -1,54 +1,49 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ELFTools
2
4
  # Define constants from elf.h.
3
5
  # Mostly refer from https://github.com/torvalds/linux/blob/master/include/uapi/linux/elf.h
4
6
  # and binutils/elfcpp/elfcpp.h.
5
7
  module Constants
6
8
  # ELF magic header
7
- ELFMAG = "\x7FELF".freeze
9
+ ELFMAG = "\x7FELF"
8
10
 
9
- # Section header types, records in +sh_type+.
10
- module SHT
11
- SHT_NULL = 0 # null section
12
- SHT_PROGBITS = 1 # information defined by program itself
13
- SHT_SYMTAB = 2 # symbol table section
14
- SHT_STRTAB = 3 # string table section
15
- SHT_RELA = 4 # relocation with addends
16
- SHT_HASH = 5 # symbol hash table
17
- SHT_DYNAMIC = 6 # information of dynamic linking
18
- SHT_NOTE = 7 # note section
19
- SHT_NOBITS = 8 # section occupies no space
20
- SHT_REL = 9 # relocation
21
- SHT_SHLIB = 10 # reserved
22
- SHT_DYNSYM = 11 # symbols for dynamic
23
- # Values between {SHT_LOPROC} and {SHT_HIPROC} are reserved for processor-specific semantics.
24
- SHT_LOPROC = 0x70000000
25
- SHT_HIPROC = 0x7fffffff # see {SHT_LOPROC}
26
- # Values between {SHT_LOUSER} and {SHT_HIUSER} are reserved for application programs.
27
- SHT_LOUSER = 0x80000000
28
- SHT_HIUSER = 0xffffffff # see {SHT_LOUSER}
29
- end
30
- include SHT
11
+ # Values of `d_un.d_val' in the DT_FLAGS and DT_FLAGS_1 entry.
12
+ module DF
13
+ DF_ORIGIN = 0x00000001 # Object may use DF_ORIGIN
14
+ DF_SYMBOLIC = 0x00000002 # Symbol resolutions starts here
15
+ DF_TEXTREL = 0x00000004 # Object contains text relocations
16
+ DF_BIND_NOW = 0x00000008 # No lazy binding for this object
17
+ DF_STATIC_TLS = 0x00000010 # Module uses the static TLS model
31
18
 
32
- # Program header types, records in +p_type+.
33
- module PT
34
- PT_NULL = 0 # null segment
35
- PT_LOAD = 1 # segment to be load
36
- PT_DYNAMIC = 2 # dynamic tags
37
- PT_INTERP = 3 # interpreter, same as .interp section
38
- PT_NOTE = 4 # same as .note* section
39
- PT_SHLIB = 5 # reserved
40
- PT_PHDR = 6 # where program header starts
41
- PT_TLS = 7 # thread local storage segment
42
- PT_LOOS = 0x60000000 # OS-specific
43
- PT_HIOS = 0x6fffffff # OS-specific
44
- # Values between {PT_LOPROC} and {PT_HIPROC} are reserved for processor-specific semantics.
45
- PT_LOPROC = 0x70000000
46
- PT_HIPROC = 0x7fffffff # see {PT_LOPROC}
47
- PT_GNU_EH_FRAME = 0x6474e550 # for exception handler
48
- PT_GNU_STACK = 0x6474e551 # permission of stack
49
- PT_GNU_RELRO = 0x6474e552 # read only after relocation
19
+ DF_1_NOW = 0x00000001 # Set RTLD_NOW for this object.
20
+ DF_1_GLOBAL = 0x00000002 # Set RTLD_GLOBAL for this object.
21
+ DF_1_GROUP = 0x00000004 # Set RTLD_GROUP for this object.
22
+ DF_1_NODELETE = 0x00000008 # Set RTLD_NODELETE for this object.
23
+ DF_1_LOADFLTR = 0x00000010 # Trigger filtee loading at runtime.
24
+ DF_1_INITFIRST = 0x00000020 # Set RTLD_INITFIRST for this object
25
+ DF_1_NOOPEN = 0x00000040 # Set RTLD_NOOPEN for this object.
26
+ DF_1_ORIGIN = 0x00000080 # $ORIGIN must be handled.
27
+ DF_1_DIRECT = 0x00000100 # Direct binding enabled.
28
+ DF_1_TRANS = 0x00000200 # :nodoc:
29
+ DF_1_INTERPOSE = 0x00000400 # Object is used to interpose.
30
+ DF_1_NODEFLIB = 0x00000800 # Ignore default lib search path.
31
+ DF_1_NODUMP = 0x00001000 # Object can't be dldump'ed.
32
+ DF_1_CONFALT = 0x00002000 # Configuration alternative created.
33
+ DF_1_ENDFILTEE = 0x00004000 # Filtee terminates filters search.
34
+ DF_1_DISPRELDNE = 0x00008000 # Disp reloc applied at build time.
35
+ DF_1_DISPRELPND = 0x00010000 # Disp reloc applied at run-time.
36
+ DF_1_NODIRECT = 0x00020000 # Object has no-direct binding.
37
+ DF_1_IGNMULDEF = 0x00040000 # :nodoc:
38
+ DF_1_NOKSYMS = 0x00080000 # :nodoc:
39
+ DF_1_NOHDR = 0x00100000 # :nodoc:
40
+ DF_1_EDITED = 0x00200000 # Object is modified after built.
41
+ DF_1_NORELOC = 0x00400000 # :nodoc:
42
+ DF_1_SYMINTPOSE = 0x00800000 # Object has individual interposers.
43
+ DF_1_GLOBAUDIT = 0x01000000 # Global auditing required.
44
+ DF_1_SINGLETON = 0x02000000 # Singleton symbols are used.
50
45
  end
51
- include PT
46
+ include DF
52
47
 
53
48
  # Dynamic table types, records in +d_tag+.
54
49
  module DT
@@ -100,6 +95,7 @@ module ELFTools
100
95
  DT_VERDEF = 0x6ffffffc # address of version definition table
101
96
  DT_VERDEFNUM = 0x6ffffffd # number of entries in {DT_VERDEF}
102
97
  DT_VERNEED = 0x6ffffffe # address of version dependency table
98
+ DT_VERSYM = 0x6ffffff0 # section address of .gnu.version
103
99
  DT_VERNEEDNUM = 0x6fffffff # number of entries in {DT_VERNEED}
104
100
  # Values between {DT_LOPROC} and {DT_HIPROC} are reserved for processor-specific semantics.
105
101
  DT_LOPROC = 0x70000000
@@ -107,43 +103,6 @@ module ELFTools
107
103
  end
108
104
  include DT
109
105
 
110
- # Values of `d_un.d_val' in the DT_FLAGS and DT_FLAGS_1 entry.
111
- module DF
112
- DF_ORIGIN = 0x00000001 # Object may use DF_ORIGIN
113
- DF_SYMBOLIC = 0x00000002 # Symbol resolutions starts here
114
- DF_TEXTREL = 0x00000004 # Object contains text relocations
115
- DF_BIND_NOW = 0x00000008 # No lazy binding for this object
116
- DF_STATIC_TLS = 0x00000010 # Module uses the static TLS model
117
-
118
- DF_1_NOW = 0x00000001 # Set RTLD_NOW for this object.
119
- DF_1_GLOBAL = 0x00000002 # Set RTLD_GLOBAL for this object.
120
- DF_1_GROUP = 0x00000004 # Set RTLD_GROUP for this object.
121
- DF_1_NODELETE = 0x00000008 # Set RTLD_NODELETE for this object.
122
- DF_1_LOADFLTR = 0x00000010 # Trigger filtee loading at runtime.
123
- DF_1_INITFIRST = 0x00000020 # Set RTLD_INITFIRST for this object
124
- DF_1_NOOPEN = 0x00000040 # Set RTLD_NOOPEN for this object.
125
- DF_1_ORIGIN = 0x00000080 # $ORIGIN must be handled.
126
- DF_1_DIRECT = 0x00000100 # Direct binding enabled.
127
- DF_1_TRANS = 0x00000200 # :nodoc:
128
- DF_1_INTERPOSE = 0x00000400 # Object is used to interpose.
129
- DF_1_NODEFLIB = 0x00000800 # Ignore default lib search path.
130
- DF_1_NODUMP = 0x00001000 # Object can't be dldump'ed.
131
- DF_1_CONFALT = 0x00002000 # Configuration alternative created.
132
- DF_1_ENDFILTEE = 0x00004000 # Filtee terminates filters search.
133
- DF_1_DISPRELDNE = 0x00008000 # Disp reloc applied at build time.
134
- DF_1_DISPRELPND = 0x00010000 # Disp reloc applied at run-time.
135
- DF_1_NODIRECT = 0x00020000 # Object has no-direct binding.
136
- DF_1_IGNMULDEF = 0x00040000 # :nodoc:
137
- DF_1_NOKSYMS = 0x00080000 # :nodoc:
138
- DF_1_NOHDR = 0x00100000 # :nodoc:
139
- DF_1_EDITED = 0x00200000 # Object is modified after built.
140
- DF_1_NORELOC = 0x00400000 # :nodoc:
141
- DF_1_SYMINTPOSE = 0x00800000 # Object has individual interposers.
142
- DF_1_GLOBAUDIT = 0x01000000 # Global auditing required.
143
- DF_1_SINGLETON = 0x02000000 # Singleton symbols are used.
144
- end
145
- include DF
146
-
147
106
  # These constants define the various ELF target machines.
148
107
  module EM
149
108
  EM_NONE = 0 # none
@@ -253,5 +212,109 @@ module ELFTools
253
212
  end
254
213
  end
255
214
  include ET
215
+
216
+ # Program header permission flags, records bitwise OR value in +p_flags+.
217
+ module PF
218
+ PF_X = 1
219
+ PF_W = 2
220
+ PF_R = 4
221
+ end
222
+ include PF
223
+
224
+ # Program header types, records in +p_type+.
225
+ module PT
226
+ PT_NULL = 0 # null segment
227
+ PT_LOAD = 1 # segment to be load
228
+ PT_DYNAMIC = 2 # dynamic tags
229
+ PT_INTERP = 3 # interpreter, same as .interp section
230
+ PT_NOTE = 4 # same as .note* section
231
+ PT_SHLIB = 5 # reserved
232
+ PT_PHDR = 6 # where program header starts
233
+ PT_TLS = 7 # thread local storage segment
234
+ PT_LOOS = 0x60000000 # OS-specific
235
+ PT_HIOS = 0x6fffffff # OS-specific
236
+ # Values between {PT_LOPROC} and {PT_HIPROC} are reserved for processor-specific semantics.
237
+ PT_LOPROC = 0x70000000
238
+ PT_HIPROC = 0x7fffffff # see {PT_LOPROC}
239
+ PT_GNU_EH_FRAME = 0x6474e550 # for exception handler
240
+ PT_GNU_STACK = 0x6474e551 # permission of stack
241
+ PT_GNU_RELRO = 0x6474e552 # read only after relocation
242
+ end
243
+ include PT
244
+
245
+ # Special indices to section. These are used when there is no valid index to section header.
246
+ # The meaning of these values is left upto the embedding header.
247
+ module SHN
248
+ SHN_UNDEF = 0 # undefined section
249
+ SHN_LORESERVE = 0xff00 # start of reserved indices
250
+ end
251
+ include SHN
252
+
253
+ # Section header types, records in +sh_type+.
254
+ module SHT
255
+ SHT_NULL = 0 # null section
256
+ SHT_PROGBITS = 1 # information defined by program itself
257
+ SHT_SYMTAB = 2 # symbol table section
258
+ SHT_STRTAB = 3 # string table section
259
+ SHT_RELA = 4 # relocation with addends
260
+ SHT_HASH = 5 # symbol hash table
261
+ SHT_DYNAMIC = 6 # information of dynamic linking
262
+ SHT_NOTE = 7 # note section
263
+ SHT_NOBITS = 8 # section occupies no space
264
+ SHT_REL = 9 # relocation
265
+ SHT_SHLIB = 10 # reserved
266
+ SHT_DYNSYM = 11 # symbols for dynamic
267
+ # Values between {SHT_LOPROC} and {SHT_HIPROC} are reserved for processor-specific semantics.
268
+ SHT_LOPROC = 0x70000000
269
+ SHT_HIPROC = 0x7fffffff # see {SHT_LOPROC}
270
+ # Values between {SHT_LOUSER} and {SHT_HIUSER} are reserved for application programs.
271
+ SHT_LOUSER = 0x80000000
272
+ SHT_HIUSER = 0xffffffff # see {SHT_LOUSER}
273
+ end
274
+ include SHT
275
+
276
+ # Symbol binding from Sym st_info field.
277
+ module STB
278
+ STB_LOCAL = 0 # Local symbol
279
+ STB_GLOBAL = 1 # Global symbol
280
+ STB_WEAK = 2 # Weak symbol
281
+ STB_NUM = 3 # Number of defined types.
282
+ STB_LOOS = 10 # Start of OS-specific
283
+ STB_GNU_UNIQUE = 10 # Unique symbol.
284
+ STB_HIOS = 12 # End of OS-specific
285
+ STB_LOPROC = 13 # Start of processor-specific
286
+ STB_HIPROC = 15 # End of processor-specific
287
+ end
288
+ include STB
289
+
290
+ # Symbol types from Sym st_info field.
291
+ module STT
292
+ STT_NOTYPE = 0 # Symbol type is unspecified
293
+ STT_OBJECT = 1 # Symbol is a data object
294
+ STT_FUNC = 2 # Symbol is a code object
295
+ STT_SECTION = 3 # Symbol associated with a section
296
+ STT_FILE = 4 # Symbol's name is file name
297
+ STT_COMMON = 5 # Symbol is a common data object
298
+ STT_TLS = 6 # Symbol is thread-local data object
299
+ STT_NUM = 7 # Number of defined types.
300
+
301
+ # GNU extension: symbol value points to a function which is called
302
+ # at runtime to determine the final value of the symbol.
303
+ STT_GNU_IFUNC = 10
304
+
305
+ STT_LOOS = 10 # Start of OS-specific
306
+ STT_HIOS = 12 # End of OS-specific
307
+ STT_LOPROC = 13 # Start of processor-specific
308
+ STT_HIPROC = 15 # End of processor-specific
309
+
310
+ # The section type that must be used for register symbols on
311
+ # Sparc. These symbols initialize a global register.
312
+ STT_SPARC_REGISTER = 13
313
+
314
+ # ARM: a THUMB function. This is not defined in ARM ELF Specification but
315
+ # used by the GNU tool-chain.
316
+ STT_ARM_TFUNC = 13
317
+ end
318
+ include STT
256
319
  end
257
320
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ELFTools
2
4
  # Define common methods for dynamic sections and dynamic segments.
3
5
  #
@@ -18,6 +20,7 @@ module ELFTools
18
20
  # Otherwise, return array of tags.
19
21
  def each_tags(&block)
20
22
  return enum_for(:each_tags) unless block_given?
23
+
21
24
  arr = []
22
25
  0.step do |i|
23
26
  tag = tag_at(i).tap(&block)
@@ -31,7 +34,7 @@ module ELFTools
31
34
  # @return [Array<ELFTools::Dynamic::Tag>]
32
35
  # Array of tags.
33
36
  def tags
34
- each_tags.to_a
37
+ @tags ||= each_tags.to_a
35
38
  end
36
39
 
37
40
  # Get a tag of specific type.
@@ -63,6 +66,18 @@ module ELFTools
63
66
  each_tags.find { |tag| tag.header.d_tag == type }
64
67
  end
65
68
 
69
+ # Get tags of specific type.
70
+ # @param [Integer, Symbol, String] type
71
+ # Constant value, symbol, or string of type
72
+ # is acceptable. See examples for more information.
73
+ # @return [Array<ELFTools::Dynamic::Tag>] The desired tags.
74
+ #
75
+ # @see #tag_by_type
76
+ def tags_by_type(type)
77
+ type = Util.to_constant(Constants::DT, type)
78
+ each_tags.select { |tag| tag.header.d_tag == type }
79
+ end
80
+
66
81
  # Get the +n+-th tag.
67
82
  #
68
83
  # Tags are lazy loaded.
@@ -76,9 +91,11 @@ module ELFTools
76
91
  # @param [Integer] n The index.
77
92
  # @return [ELFTools::Dynamic::Tag] The desired tag.
78
93
  def tag_at(n)
79
- return if n < 0
94
+ return if n.negative?
95
+
80
96
  @tag_at_map ||= {}
81
97
  return @tag_at_map[n] if @tag_at_map[n]
98
+
82
99
  dyn = Structs::ELF_Dyn.new(endian: endian)
83
100
  dyn.elf_class = header.elf_class
84
101
  stream.pos = tag_start + n * dyn.num_bytes
@@ -153,6 +170,7 @@ module ELFTools
153
170
  # @return [String, nil] The name.
154
171
  def name
155
172
  return nil unless name?
173
+
156
174
  Util.cstring(stream, @str_offset.call + header.d_val.to_i)
157
175
  end
158
176
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'elftools/constants'
2
4
  require 'elftools/exceptions'
3
5
  require 'elftools/lazy_array'
@@ -32,6 +34,7 @@ module ELFTools
32
34
  # @return [ELFTools::Structs::ELF_Ehdr] The header.
33
35
  def header
34
36
  return @header if defined?(@header)
37
+
35
38
  stream.pos = 0
36
39
  @header = Structs::ELF_Ehdr.new(endian: endian, offset: stream.pos)
37
40
  @header.elf_class = elf_class
@@ -49,9 +52,11 @@ module ELFTools
49
52
  def build_id
50
53
  section = section_by_name('.note.gnu.build-id')
51
54
  return nil if section.nil?
55
+
52
56
  note = section.notes.first
53
57
  return nil if note.nil?
54
- note.desc.unpack('H*').first
58
+
59
+ note.desc.unpack1('H*')
55
60
  end
56
61
 
57
62
  # Get machine architecture.
@@ -116,6 +121,7 @@ module ELFTools
116
121
  # otherwise, the whole sections will be returned.
117
122
  def each_sections(&block)
118
123
  return enum_for(:each_sections) unless block_given?
124
+
119
125
  Array.new(num_sections) do |i|
120
126
  section_at(i).tap(&block)
121
127
  end
@@ -188,6 +194,7 @@ module ELFTools
188
194
  # Whole segments will be returned.
189
195
  def each_segments(&block)
190
196
  return enum_for(:each_segments) unless block_given?
197
+
191
198
  Array.new(num_segments) do |i|
192
199
  segment_at(i).tap(&block)
193
200
  end
@@ -277,18 +284,15 @@ module ELFTools
277
284
  #
278
285
  # This method should work no matter ELF is a PIE or not.
279
286
  # This method refers from (actually equals to) binutils/readelf.c#offset_from_vma.
280
- # @param [Integer] vma The address need query.
281
- # @return [Integer] Offset related to file.
287
+ # @param [Integer] vma The virtual address to be queried.
288
+ # @return [Integer] Related file offset.
282
289
  # @example
283
290
  # elf = ELFTools::ELFFile.new(File.open('/bin/cat'))
284
291
  # elf.offset_from_vma(0x401337)
285
292
  # #=> 4919 # 0x1337
286
293
  def offset_from_vma(vma, size = 0)
287
294
  segments_by_type(:load) do |seg|
288
- if vma >= (seg.header.p_vaddr & -seg.header.p_align) &&
289
- vma + size <= seg.header.p_vaddr + seg.header.p_filesz
290
- return vma - seg.header.p_vaddr + seg.header.p_offset
291
- end
295
+ return seg.vma_to_offset(vma) if seg.vma_in?(vma, size)
292
296
  end
293
297
  end
294
298
 
@@ -324,6 +328,7 @@ module ELFTools
324
328
  explore = lambda do |obj|
325
329
  return obj if obj.is_a?(::ELFTools::Structs::ELFStruct)
326
330
  return obj.map(&explore) if obj.is_a?(Array)
331
+
327
332
  obj.instance_variables.map do |s|
328
333
  explore.call(obj.instance_variable_get(s))
329
334
  end
@@ -334,19 +339,21 @@ module ELFTools
334
339
  def identify
335
340
  stream.pos = 0
336
341
  magic = stream.read(4)
337
- raise ELFError, "Invalid magic number #{magic.inspect}" unless magic == Constants::ELFMAG
342
+ raise ELFMagicError, "Invalid magic number #{magic.inspect}" unless magic == Constants::ELFMAG
343
+
338
344
  ei_class = stream.read(1).ord
339
345
  @elf_class = {
340
346
  1 => 32,
341
347
  2 => 64
342
348
  }[ei_class]
343
- raise ELFError, format('Invalid EI_CLASS "\x%02x"', ei_class) if elf_class.nil?
349
+ raise ELFClassError, format('Invalid EI_CLASS "\x%02x"', ei_class) if elf_class.nil?
350
+
344
351
  ei_data = stream.read(1).ord
345
352
  @endian = {
346
353
  1 => :little,
347
354
  2 => :big
348
355
  }[ei_data]
349
- raise ELFError, format('Invalid EI_DATA "\x%02x"', ei_data) if endian.nil?
356
+ raise ELFDataError, format('Invalid EI_DATA "\x%02x"', ei_data) if endian.nil?
350
357
  end
351
358
 
352
359
  def create_section(n)
@@ -1,4 +1,15 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ELFTools
2
4
  # Being raised when parsing error.
3
5
  class ELFError < StandardError; end
6
+
7
+ # Raised on invalid ELF magic.
8
+ class ELFMagicError < ELFError; end
9
+
10
+ # Raised on invalid ELF class (EI_CLASS).
11
+ class ELFClassError < ELFError; end
12
+
13
+ # Raised on invalid ELF data encoding (EI_DATA).
14
+ class ELFDataError < ELFError; end
4
15
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ELFTools
2
4
  # A helper class for {ELFTools} easy to implement
3
5
  # 'lazy loading' objects.
@@ -37,7 +39,8 @@ module ELFTools
37
39
  # return type of block given in {#initialize}.
38
40
  def [](i)
39
41
  # XXX: support negative index?
40
- return nil if i < 0 || i >= @internal.size
42
+ return nil unless i.between?(0, @internal.size - 1)
43
+
41
44
  @internal[i] ||= @block.call(i)
42
45
  end
43
46
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'elftools/structs'
2
4
  require 'elftools/util'
3
5
 
@@ -41,6 +43,7 @@ module ELFTools
41
43
  # Otherwise, return the array of notes.
42
44
  def each_notes
43
45
  return enum_for(:each_notes) unless block_given?
46
+
44
47
  @notes_offset_map ||= {}
45
48
  cur = note_start
46
49
  notes = []
@@ -100,7 +103,8 @@ module ELFTools
100
103
  # Name of this note.
101
104
  # @return [String] The name.
102
105
  def name
103
- return @name if @name
106
+ return @name if defined?(@name)
107
+
104
108
  stream.pos = @offset + SIZE_OF_NHDR
105
109
  @name = stream.read(header.n_namesz)[0..-2]
106
110
  end
@@ -108,7 +112,8 @@ module ELFTools
108
112
  # Description of this note.
109
113
  # @return [String] The description.
110
114
  def desc
111
- return @desc if @desc
115
+ return @desc if instance_variable_defined?(:@desc)
116
+
112
117
  stream.pos = @offset + SIZE_OF_NHDR + Util.align(header.n_namesz, 2)
113
118
  @desc = stream.read(header.n_descsz)
114
119
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'elftools/dynamic'
2
4
  require 'elftools/sections/section'
3
5
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'elftools/note'
2
4
  require 'elftools/sections/section'
3
5
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'elftools/sections/section'
2
4
 
3
5
  module ELFTools
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'elftools/constants'
2
4
  require 'elftools/sections/section'
3
5
  require 'elftools/structs'
@@ -42,6 +44,7 @@ module ELFTools
42
44
  # Otherwise, the whole relocations will be returned.
43
45
  def each_relocations(&block)
44
46
  return enum_for(:each_relocations) unless block_given?
47
+
45
48
  Array.new(num_relocations) do |i|
46
49
  relocation_at(i).tap(&block)
47
50
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'elftools/constants'
2
4
  module ELFTools
3
5
  module Sections
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # Require this file to load all sections classes.
2
4
 
3
5
  require 'elftools/sections/section'
@@ -19,7 +21,7 @@ module ELFTools
19
21
  # @param [#pos=, #read] stream Streaming object.
20
22
  # @return [ELFTools::Sections::Section]
21
23
  # Return object dependes on +header.sh_type+.
22
- def create(header, stream, *args)
24
+ def create(header, stream, *args, **kwargs)
23
25
  klass = case header.sh_type
24
26
  when Constants::SHT_DYNAMIC then DynamicSection
25
27
  when Constants::SHT_NULL then NullSection
@@ -29,7 +31,7 @@ module ELFTools
29
31
  when Constants::SHT_SYMTAB, Constants::SHT_DYNSYM then SymTabSection
30
32
  else Section
31
33
  end
32
- klass.new(header, stream, *args)
34
+ klass.new(header, stream, *args, **kwargs)
33
35
  end
34
36
  end
35
37
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'elftools/sections/section'
2
4
  require 'elftools/util'
3
5
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'elftools/sections/section'
2
4
 
3
5
  module ELFTools
@@ -56,6 +58,7 @@ module ELFTools
56
58
  # Otherwise return array of symbols.
57
59
  def each_symbols(&block)
58
60
  return enum_for(:each_symbols) unless block_given?
61
+
59
62
  Array.new(num_symbols) do |i|
60
63
  symbol_at(i).tap(&block)
61
64
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'elftools/segments/segment'
2
4
  require 'elftools/dynamic'
3
5
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'elftools/segments/segment'
2
4
 
3
5
  module ELFTools
@@ -0,0 +1,91 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'elftools/segments/segment'
4
+
5
+ module ELFTools
6
+ module Segments
7
+ # For DT_LOAD segment.
8
+ # Able to query between file offset and virtual memory address.
9
+ class LoadSegment < Segment
10
+ # Returns the start of this segment.
11
+ # @return [Integer]
12
+ # The file offset.
13
+ def file_head
14
+ header.p_offset.to_i
15
+ end
16
+
17
+ # Returns size in file.
18
+ # @return [Integer]
19
+ # The size.
20
+ def size
21
+ header.p_filesz.to_i
22
+ end
23
+
24
+ # Returns the end of this segment.
25
+ # @return [Integer]
26
+ # The file offset.
27
+ def file_tail
28
+ file_head + size
29
+ end
30
+
31
+ # Returns the start virtual address of this segment.
32
+ # @return [Integer]
33
+ # The vma.
34
+ def mem_head
35
+ header.p_vaddr.to_i
36
+ end
37
+
38
+ # Returns size in memory.
39
+ # @return [Integer]
40
+ # The size.
41
+ def mem_size
42
+ header.p_memsz.to_i
43
+ end
44
+
45
+ # Returns the end virtual address of this segment.
46
+ # @return [Integer]
47
+ # The vma.
48
+ def mem_tail
49
+ mem_head + mem_size
50
+ end
51
+
52
+ # Query if the given file offset located in this segment.
53
+ # @param [Integer] offset
54
+ # File offset.
55
+ # @param [Integer] size
56
+ # Size.
57
+ # @return [Boolean]
58
+ def offset_in?(offset, size = 0)
59
+ file_head <= offset && offset + size < file_tail
60
+ end
61
+
62
+ # Convert file offset into virtual memory address.
63
+ # @param [Integer] offset
64
+ # File offset.
65
+ # @return [Integer]
66
+ def offset_to_vma(offset)
67
+ # XXX: What if file_head is not aligned with p_vaddr (which is invalid according to ELF spec)?
68
+ offset - file_head + header.p_vaddr
69
+ end
70
+
71
+ # Query if the given virtual memory address located in this segment.
72
+ # @param [Integer] vma
73
+ # Virtual memory address.
74
+ # @param [Integer] size
75
+ # Size.
76
+ # @return [Boolean]
77
+ def vma_in?(vma, size = 0)
78
+ vma >= (header.p_vaddr & -header.p_align) &&
79
+ vma + size <= mem_tail
80
+ end
81
+
82
+ # Convert virtual memory address into file offset.
83
+ # @param [Integer] vma
84
+ # Virtual memory address.
85
+ # @return [Integer]
86
+ def vma_to_offset(vma)
87
+ vma - header.p_vaddr + header.p_offset
88
+ end
89
+ end
90
+ end
91
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'elftools/note'
2
4
  require 'elftools/segments/segment'
3
5
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ELFTools
2
4
  module Segments
3
5
  # Base class of segments.
@@ -1,9 +1,12 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # Require this file to load all segment classes.
2
4
 
3
5
  require 'elftools/segments/segment'
4
6
 
5
7
  require 'elftools/segments/dynamic_segment'
6
8
  require 'elftools/segments/interp_segment'
9
+ require 'elftools/segments/load_segment'
7
10
  require 'elftools/segments/note_segment'
8
11
 
9
12
  module ELFTools
@@ -16,14 +19,15 @@ module ELFTools
16
19
  # @param [#pos=, #read] stream Streaming object.
17
20
  # @return [ELFTools::Segments::Segment]
18
21
  # Return object dependes on +header.p_type+.
19
- def create(header, stream, *args)
22
+ def create(header, stream, *args, **kwargs)
20
23
  klass = case header.p_type
21
24
  when Constants::PT_DYNAMIC then DynamicSegment
22
25
  when Constants::PT_INTERP then InterpSegment
26
+ when Constants::PT_LOAD then LoadSegment
23
27
  when Constants::PT_NOTE then NoteSegment
24
28
  else Segment
25
29
  end
26
- klass.new(header, stream, *args)
30
+ klass.new(header, stream, *args, **kwargs)
27
31
  end
28
32
  end
29
33
  end
@@ -1,10 +1,12 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'bindata'
4
+
2
5
  module ELFTools
3
6
  # Define ELF related structures in this module.
4
7
  #
5
8
  # Structures are fetched 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.
9
+ # Use gem +bindata+ to have these structures support 32/64 bits and little/big endian simultaneously.
8
10
  module Structs
9
11
  # The base structure to define common methods.
10
12
  class ELFStruct < BinData::Record
@@ -23,9 +25,13 @@ module ELFTools
23
25
  end
24
26
 
25
27
  class << self
26
- # Hook constructor, while +BinData::Record+ doesn't allow us to override +#initialize+,
27
- # so we hack +new+ here.
28
- def new(**kwargs)
28
+ # Hooks the constructor.
29
+ #
30
+ # +BinData::Record+ doesn't allow us to override +#initialize+, so we hack +new+ here.
31
+ def new(*args)
32
+ # XXX: The better implementation is +new(*args, **kwargs)+, but we can't do this unless bindata changed
33
+ # lib/bindata/dsl.rb#override_new_in_class to invoke +new+ with both +args+ and +kwargs+.
34
+ kwargs = args.last.is_a?(Hash) ? args.last : {}
29
35
  offset = kwargs.delete(:offset)
30
36
  super.tap do |obj|
31
37
  obj.offset = offset
@@ -42,18 +48,19 @@ module ELFTools
42
48
  end
43
49
  end
44
50
 
45
- # Hacking to get endian of current class
46
- # @return [Symbol, nil] +:little+ or +:big+.
51
+ # Gets the endianness of current class.
52
+ # @return [:little, :big] The endianness.
47
53
  def self_endian
48
54
  bindata_name[-2..-1] == 'be' ? :big : :little
49
55
  end
50
56
 
51
- # Pack integer into string.
57
+ # Packs an integer to string.
52
58
  # @param [Integer] val
53
59
  # @param [Integer] bytes
54
60
  # @return [String]
55
61
  def pack(val, bytes)
56
62
  raise ArgumentError, "Not supported assign type #{val.class}" unless val.is_a?(Integer)
63
+
57
64
  number = val & ((1 << (8 * bytes)) - 1)
58
65
  out = []
59
66
  bytes.times do
@@ -109,7 +116,7 @@ module ELFTools
109
116
  choice :sh_entsize, **CHOICE_SIZE_T
110
117
  end
111
118
 
112
- # Program header structure for 32bit.
119
+ # Program header structure for 32-bit.
113
120
  class ELF32_Phdr < ELFStruct
114
121
  endian :big_and_little
115
122
  uint32 :p_type
@@ -122,7 +129,7 @@ module ELFTools
122
129
  uint32 :p_align
123
130
  end
124
131
 
125
- # Program header structure for 64bit.
132
+ # Program header structure for 64-bit.
126
133
  class ELF64_Phdr < ELFStruct
127
134
  endian :big_and_little
128
135
  uint32 :p_type
@@ -134,13 +141,14 @@ module ELFTools
134
141
  uint64 :p_memsz
135
142
  uint64 :p_align
136
143
  end
137
- # Get program header class according to bits.
144
+
145
+ # Gets the class of program header according to bits.
138
146
  ELF_Phdr = {
139
147
  32 => ELF32_Phdr,
140
148
  64 => ELF64_Phdr
141
149
  }.freeze
142
150
 
143
- # Symbol structure for 32bit.
151
+ # Symbol structure for 32-bit.
144
152
  class ELF32_sym < ELFStruct
145
153
  endian :big_and_little
146
154
  uint32 :st_name
@@ -151,7 +159,7 @@ module ELFTools
151
159
  uint16 :st_shndx
152
160
  end
153
161
 
154
- # Symbol structure for 64bit.
162
+ # Symbol structure for 64-bit.
155
163
  class ELF64_sym < ELFStruct
156
164
  endian :big_and_little
157
165
  uint32 :st_name # Symbol name, index in string tbl
@@ -161,6 +169,7 @@ module ELFTools
161
169
  uint64 :st_value # Value of the symbol
162
170
  uint64 :st_size # Associated symbol size
163
171
  end
172
+
164
173
  # Get symbol header class according to bits.
165
174
  ELF_sym = {
166
175
  32 => ELF32_sym,
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ELFTools
2
4
  # Define some util methods.
3
5
  module Util
@@ -17,6 +19,7 @@ module ELFTools
17
19
  def align(num, bit)
18
20
  n = 2**bit
19
21
  return num if (num % n).zero?
22
+
20
23
  (num + n) & ~(n - 1)
21
24
  end
22
25
 
@@ -36,6 +39,7 @@ module ELFTools
36
39
  # if val is an integer, check if exists in mod
37
40
  if val.is_a?(Integer)
38
41
  return val if mod.constants.any? { |c| mod.const_get(c) == val }
42
+
39
43
  raise ArgumentError, "No constants in #{module_name} is #{val}"
40
44
  end
41
45
  val = val.to_s.upcase
@@ -43,6 +47,7 @@ module ELFTools
43
47
  val = prefix + '_' + val unless val.start_with?(prefix)
44
48
  val = val.to_sym
45
49
  raise ArgumentError, "No constants in #{module_name} named \"#{val}\"" unless mod.const_defined?(val)
50
+
46
51
  mod.const_get(val)
47
52
  end
48
53
 
@@ -61,6 +66,7 @@ module ELFTools
61
66
  c = stream.read(1)
62
67
  return nil if c.nil? # reach EOF
63
68
  break if c == "\x00"
69
+
64
70
  ret += c
65
71
  end
66
72
  ret
@@ -1,4 +1,6 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ELFTools
2
4
  # Current gem version
3
- VERSION = '1.0.1'.freeze
5
+ VERSION = '1.1.3'
4
6
  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: 1.0.1
4
+ version: 1.1.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - david942j
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-10-03 00:00:00.000000000 Z
11
+ date: 2020-08-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bindata
@@ -24,20 +24,6 @@ dependencies:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
26
  version: '2'
27
- - !ruby/object:Gem::Dependency
28
- name: codeclimate-test-reporter
29
- requirement: !ruby/object:Gem::Requirement
30
- requirements:
31
- - - "~>"
32
- - !ruby/object:Gem::Version
33
- version: '0.6'
34
- type: :development
35
- prerelease: false
36
- version_requirements: !ruby/object:Gem::Requirement
37
- requirements:
38
- - - "~>"
39
- - !ruby/object:Gem::Version
40
- version: '0.6'
41
27
  - !ruby/object:Gem::Dependency
42
28
  name: pry
43
29
  requirement: !ruby/object:Gem::Requirement
@@ -58,56 +44,56 @@ dependencies:
58
44
  requirements:
59
45
  - - "~>"
60
46
  - !ruby/object:Gem::Version
61
- version: '12.1'
47
+ version: '13.0'
62
48
  type: :development
63
49
  prerelease: false
64
50
  version_requirements: !ruby/object:Gem::Requirement
65
51
  requirements:
66
52
  - - "~>"
67
53
  - !ruby/object:Gem::Version
68
- version: '12.1'
54
+ version: '13.0'
69
55
  - !ruby/object:Gem::Dependency
70
56
  name: rspec
71
57
  requirement: !ruby/object:Gem::Requirement
72
58
  requirements:
73
59
  - - "~>"
74
60
  - !ruby/object:Gem::Version
75
- version: '3.5'
61
+ version: '3.7'
76
62
  type: :development
77
63
  prerelease: false
78
64
  version_requirements: !ruby/object:Gem::Requirement
79
65
  requirements:
80
66
  - - "~>"
81
67
  - !ruby/object:Gem::Version
82
- version: '3.5'
68
+ version: '3.7'
83
69
  - !ruby/object:Gem::Dependency
84
70
  name: rubocop
85
71
  requirement: !ruby/object:Gem::Requirement
86
72
  requirements:
87
73
  - - "~>"
88
74
  - !ruby/object:Gem::Version
89
- version: '0.47'
75
+ version: '0.59'
90
76
  type: :development
91
77
  prerelease: false
92
78
  version_requirements: !ruby/object:Gem::Requirement
93
79
  requirements:
94
80
  - - "~>"
95
81
  - !ruby/object:Gem::Version
96
- version: '0.47'
82
+ version: '0.59'
97
83
  - !ruby/object:Gem::Dependency
98
84
  name: simplecov
99
85
  requirement: !ruby/object:Gem::Requirement
100
86
  requirements:
101
87
  - - "~>"
102
88
  - !ruby/object:Gem::Version
103
- version: 0.13.0
89
+ version: '0.17'
104
90
  type: :development
105
91
  prerelease: false
106
92
  version_requirements: !ruby/object:Gem::Requirement
107
93
  requirements:
108
94
  - - "~>"
109
95
  - !ruby/object:Gem::Version
110
- version: 0.13.0
96
+ version: '0.17'
111
97
  - !ruby/object:Gem::Dependency
112
98
  name: yard
113
99
  requirement: !ruby/object:Gem::Requirement
@@ -149,6 +135,7 @@ files:
149
135
  - lib/elftools/sections/sym_tab_section.rb
150
136
  - lib/elftools/segments/dynamic_segment.rb
151
137
  - lib/elftools/segments/interp_segment.rb
138
+ - lib/elftools/segments/load_segment.rb
152
139
  - lib/elftools/segments/note_segment.rb
153
140
  - lib/elftools/segments/segment.rb
154
141
  - lib/elftools/segments/segments.rb
@@ -167,15 +154,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
167
154
  requirements:
168
155
  - - ">="
169
156
  - !ruby/object:Gem::Version
170
- version: 2.1.0
157
+ version: '2.3'
171
158
  required_rubygems_version: !ruby/object:Gem::Requirement
172
159
  requirements:
173
160
  - - ">="
174
161
  - !ruby/object:Gem::Version
175
162
  version: '0'
176
163
  requirements: []
177
- rubyforge_project:
178
- rubygems_version: 2.5.2
164
+ rubygems_version: 3.1.2
179
165
  signing_key:
180
166
  specification_version: 4
181
167
  summary: ELFTools - Pure ruby library for parsing and patching ELF files