elftools 1.0.1 → 1.1.3

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
- 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