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 +5 -5
- data/lib/elftools.rb +2 -0
- data/lib/elftools/constants.rb +142 -79
- data/lib/elftools/dynamic.rb +20 -2
- data/lib/elftools/elf_file.rb +17 -10
- data/lib/elftools/exceptions.rb +11 -0
- data/lib/elftools/lazy_array.rb +4 -1
- data/lib/elftools/note.rb +7 -2
- data/lib/elftools/sections/dynamic_section.rb +2 -0
- data/lib/elftools/sections/note_section.rb +2 -0
- data/lib/elftools/sections/null_section.rb +2 -0
- data/lib/elftools/sections/relocation_section.rb +3 -0
- data/lib/elftools/sections/section.rb +2 -0
- data/lib/elftools/sections/sections.rb +4 -2
- data/lib/elftools/sections/str_tab_section.rb +2 -0
- data/lib/elftools/sections/sym_tab_section.rb +3 -0
- data/lib/elftools/segments/dynamic_segment.rb +2 -0
- data/lib/elftools/segments/interp_segment.rb +2 -0
- data/lib/elftools/segments/load_segment.rb +91 -0
- data/lib/elftools/segments/note_segment.rb +2 -0
- data/lib/elftools/segments/segment.rb +2 -0
- data/lib/elftools/segments/segments.rb +6 -2
- data/lib/elftools/structs.rb +22 -13
- data/lib/elftools/util.rb +6 -0
- data/lib/elftools/version.rb +3 -1
- metadata +13 -27
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: ef6779875e27077da47848a95cef46ee26be52e56e763c0850dbd2e22e7e100b
|
4
|
+
data.tar.gz: a9b422a4fb0a11a08036e222475110f9a9f6f788ce8c775d6e67d0e6f1b5a9c6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 13f82b3b243a09531408986b1acef31556089bca5927077c9e4d490632229f77cef97f9fdd1eb4343be8dc9bbb9f55e57b3ee51f5da5651009bd4b4ac3724eb5
|
7
|
+
data.tar.gz: 276ad11bcc135f067046694da526da5078cfdc0b24137cadeb7d8c52b0ddb462b23ee7d47c97bc08611160d436240c559ff1b4d18b51ed78a0b607c0973dc913
|
data/lib/elftools.rb
CHANGED
data/lib/elftools/constants.rb
CHANGED
@@ -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"
|
9
|
+
ELFMAG = "\x7FELF"
|
8
10
|
|
9
|
-
#
|
10
|
-
module
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
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
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
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
|
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
|
data/lib/elftools/dynamic.rb
CHANGED
@@ -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
|
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
|
data/lib/elftools/elf_file.rb
CHANGED
@@ -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
|
-
|
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
|
281
|
-
# @return [Integer]
|
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
|
-
|
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
|
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
|
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
|
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)
|
data/lib/elftools/exceptions.rb
CHANGED
@@ -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
|
data/lib/elftools/lazy_array.rb
CHANGED
@@ -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
|
42
|
+
return nil unless i.between?(0, @internal.size - 1)
|
43
|
+
|
41
44
|
@internal[i] ||= @block.call(i)
|
42
45
|
end
|
43
46
|
end
|
data/lib/elftools/note.rb
CHANGED
@@ -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
|
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/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 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
|
|
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
|
@@ -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,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
|
data/lib/elftools/structs.rb
CHANGED
@@ -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
|
-
#
|
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
|
-
#
|
27
|
-
#
|
28
|
-
|
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
|
-
#
|
46
|
-
# @return [
|
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
|
-
#
|
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
|
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
|
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
|
-
|
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
|
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
|
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,
|
data/lib/elftools/util.rb
CHANGED
@@ -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
|
data/lib/elftools/version.rb
CHANGED
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.
|
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:
|
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: '
|
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: '
|
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.
|
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.
|
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.
|
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.
|
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.
|
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.
|
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.
|
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
|
-
|
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
|